2011-08-30 2 views
13

Hibernate предоставляет (по крайней мере) два варианта решения проблемы с запросом N + 1. Один устанавливает FetchMode в Subselect, который генерирует выбор с помощью IN-предложения и подзаголовка внутри этого IN-предложения. Другой - указать BatchSize, который генерирует выбор с IN-предложением, содержащим идентификаторы родителей.Hibernate Subselect vs Batch Fetching

Оба работают, но я обнаружил, что опция Subselect часто сталкивается с проблемами производительности из-за того, что запрос для родителей является сложным. С другой стороны, при большом BatchSize (скажем 1000) количество запросов и сложность этих запросов очень малы.

Мой вопрос: таким образом, когда вы используете Subselect FetchMode Hibernate для BatchSize? Subselect, вероятно, имеет смысл, если у вас очень большое число родительских записей (тысячи), но есть ли другие сценарии, где вы предпочитаете Subselect to BatchSize?

EDIT: Я заметил разницу между ними при работе с нетерпением. Если у вас есть установленная ассоциация xToMany, которая будет загружаться с нетерпением и с помощью подзапроса, она генерирует такой подселек, как если бы она была ленивой. Однако если вы укажете BatchSize, сгенерированный запрос использует внешнее соединение вместо отдельного запроса. Есть ли способ заставить Hibernate использовать отдельный пакетный запрос при загрузке с нетерпением?

ответ

13

Я не использую subselect, потому что его трудно контролировать. В очень большой системе, которая имеет сложную бизнес-логику и большую команду, работающую над ней, слишком сложно сказать, какие запросы используются. Subselect может работать в определенных случаях, когда вы точно знаете, какой запрос выполняется.

Пакетная загрузка имеет некоторые большие преимущества. Это не всегда самый быстрый, но обычно достаточно быстрый. С другой стороны, он очень стабилен, не имеет побочных эффектов и полностью прозрачен для бизнес-логики. Я никогда не использую значения партии выше 100. Достаточно уменьшить N + 1 до некоторого разумного количества запросов.

+2

Я не понимаю, почему подзапрос трудно контролировать. Можете ли вы проливать свет? –

+0

Subselect зависит от запроса, который был выполнен ранее. Этот запрос может быть очень сложным, например. используя множество других таблиц и фильтрацию неиндексированными столбцами. Поэтому трудно сказать, может ли подход подзапроса повысить производительность. –

+1

Еще одна проблема с подзапросом может возникнуть с MySQL; MySQL (5.5 и ниже) имеет ужасную производительность с вложенными запросами, поскольку он принудительно делает их коррелированными и переоценивает их для каждой строки в родительском запросе. Я не могу найти другого способа для Hibernate генерировать вложенный запрос для аннотированных отношений, поэтому избежать подзапроса предотвратит неприятный сюрприз MySQL. –

2

Я нашел this article, чтобы быть полезным. Я считаю, что пакетная выборка может применяться как для коллекции, так и для родителя, тогда как подзапрос может применяться только к коллекции.

В случае стратегии выборки для коллекций подсекция будет выполняться один раз (поскольку размер партии фактически бесконечен), а при пакетной выборке оператор SQL может выполняться несколько раз.