Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > jpa pagination медленно работает


Автор: dementiev 16.2.2010, 01:15
делаю пагинацию, включён кэш 2го уровня. Через хибер работает нормально, через jpa же работает в пару раз медленнее. 
Код

       final String hql = "from Employee e "
               + "left join fetch e.positionedEmployees as p "
               + "left join fetch p.address as a "
               + "left join fetch p.company as c "
               + "left join fetch a.city as city "
               + "left join fetch city.country as country "
               + "order by e.id";

return (List<Employee>) getJpaTemplate().execute(new JpaCallback() {

           public Object doInJpa(EntityManager em) throws PersistenceException {
               Query query = em.createQuery(hql);
               query.setFlushMode(FlushModeType.COMMIT); //synchronize with db
               query.setHint("org.hibernate.cacheable", true);//2nd level cache
               query.setFirstResult(startNumber);
               query.setMaxResults( numberToRetrieve);
               List result = query.getResultList();
               return result;
           }
       });



Проблемы:
1) работает гораздо медленнее, чем через хибер+критерию
2) запрос кэшируется, т.е. новые запросы берутся из кэша.
В хибере тоже стоит кэш, но там он срабатывает, если я беру ту страницу, которую уже брал.
В jpa же он всегда срабатывает(не пойму откуда у него уже есть запрос с такими параметрами!)
буду рад ответам). Под параметрами я подразумеваю startNumber и numberToRetrieve.
Отключил эту строку: 
Код

query.setHint("org.hibernate.cacheable", true);//2nd level cache


теперь запросы не кэшируются, но работает гораздо медленнее, чем через хибер + критерию.

Автор: dementiev 17.2.2010, 19:11
суть ошибки кратко: 
jpa тянет сразу все данные, несмотря на 

Код

query.setFirstResult(startNumber);
query.setMaxResults( numberToRetrieve);


Поменял left join на inner join - стало работать быстрее, т.к. берётся меньше объектов. 
Но, почему в хибере ограничения для пагинации срабатывают, а в jpa нет?

Автор: dementiev 18.2.2010, 15:52
переделал через jpa+criteria - стало работать быстрее, чем через hibernate+criteria. Единственный минус - 100ая страница(на каждой по 100 записей) берётся около 2х секунд, первые 10 страниц - около 0 секунд.
Код

        return (List<MyObject>) getJpaTemplate().execute(new JpaCallback() {

            public Object doInJpa(EntityManager em) throws PersistenceException {
                Criteria criteria = ((Session) em.getDelegate()).createCriteria(MyObject.class);
                criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
                //int pageNumber = 20;
                criteria.setCacheable(true);
                criteria.setFirstResult(startNumber);
                criteria.setMaxResults(numberToRetrieve);
                List<MyObject> result = criteria.list();              
                return result;
            }
        });


Облазил весь гугль, так и не понял, почему jpa+hql сразу брало все записи в память, несмотря на 
Код

               query.setFirstResult(startNumber);
               query.setMaxResults( numberToRetrieve);

 

Автор: Restavrator 19.2.2010, 18:08

Для точного ответа надо смотреть конкретную реализацию, но думаю дело в следующем (по крайне мере для 1 примера):

Запрос использует join для "подтягивания" данных по схеме one-to-many

Т.к. пагинация делается для корневого класа, то  в этом случае простого ограничения на выбор строк в запросе недостаточно.
Поэтому JPA делает пагинацию в памяти.
А хибернейт делает ограничение по выбираемым строкам, но количество корневых объектов не всегда будет равно размеру страницы.

Хибернейт в более старой версии тоже использовал в таком случае пагинацию в памяти, но потом поменял подход.

Автор: dementiev 20.2.2010, 16:36
Restavrator, я так и понял, но нигде не нашёл доказательств этому. Спасибо за объяснение.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)