JPA / Hibernate, кажется, конвертирует запрос с предложением in в несколько запросов с = предложениями - PullRequest
5 голосов
/ 02 апреля 2019

Решение, которое мы реализовали для того, чтобы собрать большое количество тяжелых объектов в разумные сроки и без переполнения памяти (я говорю об объектах с несколькими отношениями fetchType.eager, к сущностям, которые сами имеют нетерпеливые извлеченные отношения), заключалось в том, чтобы сначала выберите идентификаторы этих объектов, а затем выберите сами объекты на основе этих идентификаторов.

Пришло время оптимизировать наш код, и мы заметили (используя hibernate.show_sql=true), что запрос, который мы использовали для сбора этих объектов (select a from A a where a.id in :ids), преобразуется JPA / Hibernate в тысячи запросов вида select a from ...endless join list... where a.id = ?

Вопрос в следующем:

Почему JPA / Hibernate преобразует наш начальный запрос с предложением «in» в такое большое количество запросов с предложениями «=». Разве это не неэффективно? Если так, есть ли способ предотвратить это?

Вот как в нашем коде вызывается запрос:

    Query q = this.getContext().createQuery("select a from A a where a.id in :ids");
    q.setParameter("ids", idList);
    return (List<A>) q.getResultList();

Ответы [ 3 ]

1 голос
/ 15 апреля 2019

Привет, вы должны использовать setParameterList вместо setParameter.Также нет необходимости использовать select в спящем режиме, если вы хотите получить полный объект сущности.

 Query q = this.getContext().createQuery("from A a where a.id in (:ids)");
q.setParameterList("ids", idList);
return (List<A>) q.getResultList();
0 голосов
/ 31 мая 2019

Хотя я до сих пор не могу объяснить, почему генерируется запрос для каждого идентификатора, указанного в предложении in (указанном в моем исходном вопросе), я нашел решение этой проблемы в этом блоге (https://thoughts -on-java.org/fetch-multiple-entities-id-hibernate/).Решение состоит в том, чтобы использовать сессионный API Hibernate следующим образом:

//get session object from entity manager
Session session = em.unwrap(Session.

MultiIdentifierLoadAccess<A> multiLoadAccess = session.byMultipleIds(A.class);
List<A> aObjects= multiLoadAccess.withBatchSize(1000).multiLoad(idList);
return aObjects;
0 голосов
/ 09 апреля 2019

Если ваш idList больше 1000 элементов, вы, вероятно, нажмете эту специфическую для Oracle деоптимизацию https://hibernate.atlassian.net/browse/HHH-9299.

Один из способов решить эту проблему - разбить idList на несколько кусков, выполнитьзапрос для каждого и объединить результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...