HQL присоединился к запросу, чтобы получить большое количество связей
Мой проект недавно обнаружил, что Hibernate может использовать несколько уровней отношений и стремиться получить их в едином HQL-соединении, чтобы получить заполненный объект, который нам нужен. Мы любим эту функцию, полагая, что она превзойдет обстоятельства ленивого выбора.
Проблема в том, что мы попадаем в ситуацию, когда один родитель имеет около дюжины прямых отношений, несколько из них - несколько, а в нескольких случаях - несколько десятков строк. В результате получается довольно большой перекрестный продукт, в результате которого hql вращает свои колеса практически вечно. Мы включили регистрацию до 11 и увидели более 100000 итераций, прежде чем мы сдались и убили его.
Ясно, что хотя эта техника отлично подходит для некоторых ситуаций, она имеет ограничения, как и все в жизни. Но что для этого лучше всего подходит в спящем режиме? Мы не хотим их лениво загружать, потому что мы попадем в ситуацию N+1, которая будет еще хуже.
В идеале я бы хотел, чтобы Hibernate предварительно извлекал все строки и детали, но делал это по одному за раз, а затем гидратировал нужный объект детализации к нужному родителю, но я понятия не имею, делает ли он такую вещь.
Предложения?
ОБНОВИТЬ:
Таким образом, мы получили SQL, сгенерированный этим запросом. Оказалось, что я неправильно поставил проблему. Совокупный продукт не так уж огромен. Мы выполнили тот же запрос в нашей базе данных напрямую и вернули 500 строк всего за секунду.
Тем не менее, мы очень четко увидели в журнале гибернации, что он делает 100 000 итераций. Возможно ли, что Hibernate попадет в петлю ваших отношений или что-то в этом роде?
Или, может быть, это следует задать как новый вопрос?
1 ответ
Наша команда использует специальную стратегию для работы с ассоциациями. Коллекции ленивы, одиночные отношения тоже ленивы, за исключением ссылок с простой структурой (например, ссылка на страну). И мы используем fluent-hibernate, чтобы загрузить то, что нам нужно в конкретной ситуации. Это просто потому, что свободно-гибернация поддерживает вложенные проекции. Вы можете обратиться к этому модульному тесту, чтобы увидеть, как сложная сеть объектов может быть частично загружена. Фрагмент кода из модульного теста
List<Root> roots = H.<Root> request(Root.class).proj(Root.ROOT_NAME)
.innerJoin("stationarFrom.stationar", "stationar")
.proj("stationar.name", "stationarFrom.stationar.name")
.eq(Root.ROOT_NAME, rootName).transform(Root.class).list();
Смотрите также
Как преобразовать плоский набор результатов, используя Hibernate