Стратегия извлечения в спящем режиме - когда использовать «соединение», а когда «выбрать» - PullRequest
47 голосов
/ 06 марта 2009

Большинство ассоциаций Hibernate поддерживают параметр "fetch":

fetch="join|select"

со значением "select", являющимся значением по умолчанию.

Как решить, какой использовать для какой ассоциации?

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

Спасибо.

Ответы [ 6 ]

41 голосов
/ 06 марта 2009

Присоединение должно решить проблему n + 1. Если у вас есть 10 родителей, у каждого из которых 10 детей, для объединения потребуется один запрос, а для выбора потребуется 11 (один для родителей и один для детей каждого из родителей). Это может не иметь большого значения, если база данных находится на том же сервере, что и приложение, или если сеть действительно быстрая, но если есть задержка при каждом вызове базы данных, она может сложиться. Метод соединения немного менее эффективен в исходном запросе, потому что вы дублируете родительские столбцы в каждой строке, но вы совершаете только одну обратную передачу в базу данных.

Обычно, если я знаю, что мне понадобятся дети всех родителей, я иду с join. Если мне нужны только дети от нескольких родителей, я использую select.

9 голосов
/ 06 марта 2009

Select будет выбирать дочерние элементы, отправляя им новый запрос к базе данных. Join будет получать дочерние элементы, объединяя их в запросе родителя. Вот почему вы наблюдаете аналогичную производительность даже при уменьшении количества запросов.

Выберите:

SELECT * FROM parent WHERE id=(whatever)
SELECT * FROM child WHERE id=(parent.child.id)

Регистрация:

SELECT *
FROM parent
LEFT OUTER JOIN child ON parent.child.id=child.id
WHERE parent.id=(whatever)

Что касается того, когда использовать один над другим ... Не совсем уверен. Скорее всего, это зависит от системы баз данных. Если бы один был всегда лучше другого, я сомневаюсь, что они потрудились бы дать вам возможность! Если вы видите похожую производительность для каждого из них, я бы не беспокоился об этом.

2 голосов
/ 24 апреля 2015

Если у родителя много детей, а у этих детей, в свою очередь, много других, то в этом случае первоначальное «соединение» может задушить сеть. Я предлагаю использовать «выбор» в этом случае, чтобы разделить выборки.

1 голос
/ 29 июня 2016

JOIN является предпочтительным, как правило, из соображений производительности.

Одной из причин использования SELECT является то, что вы просматриваете результаты (устанавливая смещение и лимит), которые имеют отношение «многие ко многим». Если вы используете JOIN, корневая сущность будет отображаться несколько раз, если она содержит несколько дочерних элементов «многие ко многим», и эти «копии» будут считаться с вашим пределом (даже если Hibernate свернет их после факта, используя DISTINCT_ROOT_ENTITY).

1 голос
/ 08 октября 2013

выборка = "присоединиться" Если вы выполните fetching = "join", он получит всю информацию в одном операторе select.

выборка = "выбрать" если вы хотите поставить второй оператор select для выборки связанной коллекции, то в этом случае вы будете использовать fetch = "select".

источник: Стратегии извлечения из спящего режима

0 голосов
/ 14 апреля 2015

Люди всегда говорят о снижении производительности, используя fetch = JOIN . Но, как я полагаю, для нас важно понять количество родительских / дочерних записей, которые мы получаем:

Если вы хотите получить только одну родительскую запись и ожидаете, что у нее мало детей, тогда я бы предложил вам использовать fetch = SELECT .

Если вы хотите получить все родительские записи, включая дочерние, то лучше было бы перейти на fetch = JOIN

Просто добавлю примечание, что, если записи лениво извлекают детей ( lazy = true ), то не имеет смысла использовать fetch = JOIN , так как все родительские и дочерние записи загружаются за один раз.

...