Прежде всего, небольшое замечание по терминологии. Подзапрос в SQL является частью запроса, который сам по себе является запросом, например:
SELECT ProductName
FROM Product
WHERE Id IN (SELECT ProductId
FROM OrderItem
WHERE Quantity > 100)
В этом случае следующий фрагмент запроса является подзапросом:
SELECT ProductId
FROM OrderItem
WHERE Quantity > 100
Таким образом, вы используете термин "подзапрос" здесь неправильно. В документации mybatis используется термин вложенный выбор .
Есть два способа получить связанные объекты / коллекции в mybatis. Вот соответствующая часть документации :
Вложенный выбор: путем выполнения другого сопоставленного оператора SQL, который возвращает
сложный тип желаемый. Вложенные результаты: используя вложенный результат
сопоставления для обработки повторяющихся подмножеств объединенных результатов.
Когда используется вложенный выбор, mybatis сначала выполняет основной запрос (в вашем случае selectBlog
), а затем для каждой записи выполняет другой выбор (отсюда и имя nested select
), чтобы выбрать связанные Post
сущности.
Когда используется Nested results
, выполняется только один запрос, но к нему уже присоединены данные ассоциации. Таким образом, mybatis отображает результат на структуру объекта.
В вашем примере возвращается одна сущность Blog
, поэтому при использовании nested select
выполняются два запроса, но в общем случае (если вы получите список Blog
s) вы столкнетесь с проблемой N+1
.
Теперь давайте разберемся с производительностью. Все нижеприведенное предполагает, что запросы настроены (так как нет отсутствующих индексов), вы используете пул соединений, база данных размещена, в сущности говоря, ваша система настроена во всех других отношениях.
Говоря о спектакле, единого правильного ответа не существует, и вы можете различаться. Вам всегда нужно тестировать ваши конкретные рабочие процессы в вашей настройке. Учитывая, что на производительность влияют многие факторы, такие как распределение данных (например, максимальные / минимальные / arg сообщения в каждом блоге), размер записи в БД (например, количество и размер полей данных в блоге и записи), параметры БД ( например, тип диска и скорость, объем памяти, доступной для кэширования набора данных и т. д.) может не быть единственного ответа, только некоторые общие наблюдения, которые следуют.
Но мы можем понять разницу в производительности, если мы посмотрим на случаи на концах спектра производительности. Хотелось бы увидеть случаи, когда nested select
значительно опережает join
и наоборот.
Для извлечения коллекции соединение должно быть лучше в большинстве случаев, потому что задержка в сети для выполнения N+1
количества запросов.
Один случай, когда nested select
может быть лучше, связан с взаимно однозначным сопоставлением, когда запись в основной таблице ссылается на какую-то другую таблицу, а количество элементов в другой таблице невелико, а размер записи в другой таблице большой.
Например, давайте рассмотрим Blog
, обладающее свойством category
, которое ссылается на таблицу categories
, и может иметь одно из этих значений Science, Fashion, News
. И давайте представим, что список блогов выбирается каким-то фильтром, например, ключевыми словами в заголовке блога. Если результат содержит, скажем, 500 элементов, то большинство связанных категорий будут дубликатами.
Если мы выберем их с помощью join, каждая запись в наборе результатов будет содержать Category
полей данных (и в качестве напоминания большинство из них являются дубликатами, и у нас есть много данных в записи Category
).
Если мы выберем их с помощью вложенного выбора, мы сделаем запрос для выборки категории по идентификатору категории для каждой записи, и здесь кеш mybatis сеанса начинает работать. В течение SqlSession
каждый раз, когда mybatis выполняет запрос, он сохраняет свой результат в кеше сеанса, поэтому он не выполняет повторяющиеся запросы к базе данных, а извлекает их из кеша. Это означает, что после того, как mybatis получит некоторую категорию по идентификатору для первой записи, он будет использовать ее для всех других записей в наборе записей, который он обрабатывает.
В приведенном выше примере мы выполняем до 4 запросов к базе данных, но уменьшенный объем данных, передаваемых по сети, может перевесить необходимость выполнения 4 запросов.