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

Другие вопросы по тегам