Hibernate Pagination с использованием HQL - PullRequest
4 голосов
/ 26 января 2012

Hibernate Pagination Issue

У меня есть проблема, связанная с Hibernate Pagination, и в некоторой степени это было объяснено в

Mysql Pagination Optimization

Использование Hibernate ScrollableResults для медленного чтения 90 миллионов записей

Hibernate - разбиение на страницы HQL

Проблемы сНумерация страниц и сортировка

Hibernate Row Pagination

Подробности

HQLЗапрос из приложения:

Query q = session.createQuery("from RequestDao r order by r.id desc");
            q.setFirstResult(0);
            q.setMaxResults(50);

Запрос возвращает 3 миллиона записей, и для разбивки на страницы мы устанавливаем только 50 из этих записей, страница разбиения на страницы очень медленная, потому что при каждом обновлении мы вызываем запрос, который получает 3миллионы записей, и из них мы только установили 50 записей.

Мой главный вопрос:

Всегда ли HQL работает и обращается к базе данных, или он обращается к сеансу или памяти для поиска данных, и каждый раз, когда он обращается к базе данных и получаетнабор результатов, то это очень правильно с точки зрения производительности, что было бы лучшим решением для его улучшения?

Используя HQL в hibernate, есть ли способ, которым мы можем запросить базу данных и получить только 50 записей в первую очередь изатем получите другие записи в соответствии с требованиями пользователя.Эта задача на самом деле застревает в приложении, и как лучше всего решить эту проблему?

Запрос HQL, сгенерированный в журналах

from com.delta.dao.RequestDao r order by r.id desc

Сгенерированный HibernateЗапрос

select
    getrequest0_.ID as ID24_,
    getrequest0_.TIME as START3_24_,
    getrequest0_.STAT as STATUS24_,
    getrequest0_.SUM as SUMMARY24_,
    getrequest0_.OUTNAME as OUTPUT7_24_,
    getrequest0_.INPNAME as INPUT8_24_,
    getrequest0_.REQUEST_DATE as requestT9_24_,
    getrequest0_.PARENT_ID as PARENT10_24_,
    getrequest0_.INTER_TYPE as INTERPO60_24_,
    getrequest0_.OPEN_INT as OPEN61_24_,
    getrequest0_.SOURCE_TYPE as SOURCE62_24_,
    getrequest0_.TARGET_TYPE as TARGET20_24_,
    getrequest0_.SOURCE as SOURCE14_24_,
    getrequest0_.COPY_DATA as COPY16_24_,
    getrequest0_.CURVE as GENERATE63_24_,
    getrequest0_.TITLE as TITLE24_,
    getrequest0_.TIME_ID as TIMESERIES12_24_,
    getrequest0_.TASK_NAME as TASK51_24_ 
from
    REQUEST getrequest0_ 
where
    getrequest0_.KIND='csv' 
order by
    getrequest0_.ID desc

Вот План объяснения для запроса:


 | id | select_type | table        | type | possible_keys  | key        | key_len | ref          |  rows    | filtered | Extra       | 
 |  1 | SIMPLE      | getrequest0_ | ref  | TR_KIND_ID     | TR_KIND_ID | 6       | const        | 1703018  |   100.00 | Using where |

Дополнительноинформация: время выполнения запроса с и без заказа по условию на 50 записей. Ограничение


Если я запускаю запрос with order, тогда запрос принимает 0,0012 с с настройкой предложений LIMIT 50 и without order, тот же запрос занимает 0,0032 с с тем же LIMIT 50.


Также, как мы можем найти, если:

  1. Особый HQL-запрос поражает базу данных, а не кеширует или получает информацию из сеанса?
  2. Правда ли, чтоHQL Query всегда будет идти и нажимать на базу данных, чтобы получить результат, а Criteria будет переходить на сессию или кэш и получать результаты из него?
  3. Также в моем приведенном ниже запросе:

    a) Query q = session.createQuery("from RequestDao r order by r.id desc");
    b) q.setFirstResult(0);
    c) q.setMaxResults(50);
    

в точке a, верно ли, что мы получаем результат из базы данных и сохраняем его в памяти или где, если нет, в это время у нас есть 3 миллиона результатов в наборе результатов, а затем в b и c мы устанавливаем смещениезначение и предел, поэтому на странице мы увидим только 50 результатов, так что теперь, где остаются 3 миллиона записей, и во время нашего второго вызова этого запроса мы снова перейдем к базе данных и получим 3 миллиона записей и поместим их в память, а затем снова в cМы установили 50 рекордов и продолжаем.

Эта проблема не ясна для меня, и поэтому я был бы очень признателен, если бы кто-то смог дать четкое и подробное объяснение того, как это работает и что было бы лучшим решением для этой проблемы.

Обновление

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

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

Ответы [ 2 ]

5 голосов
/ 26 января 2012

Ваш запрос указывает базе данных отсортировать все записи, которые удовлетворяют предложению WHERE. Он потенциально может отсортировать миллионы записей, прежде чем вернуть вам топ-50.

РЕДАКТИРОВАТЬ 1/26: Теперь, когда конкретные вопросы прояснены, я постараюсь ответить более конкретно.

  1. Каждый раз, когда вы выполняете такой запрос, Hibernate отправляется в базу данных. Более того, он сбрасывает все новые / обновленные данные в сеансе на диск. Если это ваша ситуация, такое поведение может способствовать медлительности.

  2. Использование Hibernate Query API обычно довольно хорошо работает в большинстве ситуаций и совместимо с широким спектром платформ баз данных. Если вы действительно обеспокоены выжатием последней капли производительности из уровня доступа к данным, вы можете написать собственный собственный запрос SQL, чтобы выбрать 50 лучших результатов. Но как только вы это сделаете, вы почти наверняка потеряете независимость от базы данных. Итак, оцените ваши затраты и выгоды.

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

РЕДАКТИРОВАТЬ 1/27: ОК. Похоже проблема в общем оформлении страницы. Я использовал AJAX последние 7 лет или около того, поэтому обычно не приходится ждать, пока фильтрующие элементы пользовательского интерфейса перерисовываются при просмотре страниц таблицы. Я полагаю, переключение каркасов пользовательского интерфейса в вашем случае не вариант. Вы должны выяснить, как оптимизировать загрузку данных для выпадающих списков и тому подобное. Эти данные часто меняются? Вы можете кешировать это где-нибудь в приложении? Если вам приходится загружать их каждый раз, можете ли вы просто получить строки дисплея вместо целых объектов?

1 голос
/ 26 января 2012

Если вы установите первый результат и максимальное количество результатов, Hibernate будет извлекать только эти записи из базы данных. Если это медленно, установите для max результатов значение 1 и включите ведение журнала SQL, чтобы увидеть, какие ассоциации также загружены.

Hibernate также поддерживает несколько кэшей: * кэш первого уровня: будет использоваться только во время одного сеанса Hibernate, который часто соответствует одной транзакции * кэш второго уровня: используется за границами сеанса / транзакции, но в основном только методом поиска по идентификатору * кеш запроса: если включен Hibernate, сначала будет искать результаты запроса оттуда. Однако запрос должен быть одинаковым с точки зрения HQL и параметров, чтобы каждая страница могла быть загружена из БД один раз, а затем кэширована. (Для получения дополнительной информации посмотрите здесь: http://docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-querycache)

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

...