簡體   English   中英

使用HQL進行Hibernate分頁

[英]Hibernate Pagination using HQL

Hibernate分頁問題

我有一個與Hibernate分頁有關的問題,並且在某種程度上已經解釋了這個問題

Mysql分頁優化

使用Hibernate的ScrollableResults慢慢讀取9000萬條記錄

Hibernate - HQL分頁

分頁和排序的問題

Hibernate Row Pagination

細節

來自應用程序的HQL查詢:

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

查詢返回300萬條記錄,對於分頁,我們只設置了50條記錄,分頁頁面非常慢,因為在每次刷新時我們都會調用查詢來獲取3百萬條記錄,而我們只設置50條記錄。

我的主要問題是

HQL是否總是進入並命中數據庫,或者它是否會進入會話或內存以查找數據,如果它每次都進入數據庫並獲得結果集那么從性能的角度來看它是非常合適的,什么是最好的解決方案來改進它?

在hibernate中使用HQL有一種方法可以查詢數據庫並首先獲取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個記錄限制上查詢帶有和不帶order by子句的運行時間


如果我with order子句運行查詢with order那么查詢需要0.0012s並設置LIMIT 50without order子句,同一查詢需要0.0032s且具有相同的LIMIT 50


另外,我們如何找到:

  1. 特定的HQL查詢是命中數據庫而不是緩存或從會話中獲取信息?
  2. 是否真的HQL查詢總是會命中數據庫以獲得結果,而Criteria會進入並點擊會話或緩存並從中獲取結果?
  3. 另外在我下面提到的查詢中:

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

在a,我們從數據庫獲得結果並將其存儲在內存中,或者如果沒有,並且此時我們在結果集中有300萬個結果,然后在b和c我們設置偏移值並限制在頁面上我們會這樣,這是真的嗎?只看到50個結果,所以現在剩下3百萬條記錄,在我們第二次調用這個查詢時,我們再次進入數據庫並獲取300萬條記錄並將它們放入內存然后在c再次設置50條記錄並繼續上。

這個問題對我來說並不清楚,因此如果有人能夠提供明確而詳細的解釋,說明這是如何工作的,以及什么是解決這個問題的最佳解決方案,我們將非常感激。

更新

事實證明,問題與頁面上的記錄顯示無關,但我在該頁面上有過濾器,並且每次請求都會從數據庫中再次獲取所有下拉值,並且在那里有一些時髦的事情發生在那里導致頁面加載時間增加。

我正在對數據庫進行多個嵌套的hibernate查詢並獲得結果,這個問題的最佳解決方案是什么?

您的查詢告訴數據庫對所有滿足WHERE子句的記錄進行排序。 它有可能在返回前50之前對數百萬條記錄進行排序。

編輯1/26:現在澄清了具體問題,我將嘗試更具體地回答。

  1. 每次執行這樣的查詢時,Hibernate都會進入數據庫。 更重要的是,它會將會話中的所有新/更新數據刷新到磁盤。 如果這是您的情況,此行為可能會導致緩慢。

  2. 使用Hibernate查詢API通常在大多數情況下都能很好地運行,並且與各種各樣的數據庫平台兼容。 如果您真的擔心從數據訪問層中擠出最后一滴性能,您可以編寫自己的本機SQL查詢來選擇前50個結果。 但是一旦你這樣做,你幾乎肯定會失去數據庫獨立性。 因此,評估您的成本與收益。

您的查詢運行時間似乎在單毫秒范圍內。 這通常與在磁盤上存儲數據的關系數據庫一樣好。 所以你可能想評估一下你是否確實遇到了性能問題。

編輯1/27:好的。 它看起來像頁面整體設計中的問題。 我在過去7年左右一直在使用AJAX,所以我通常不必等待過濾UI控件在瀏覽表格時重繪。 我想,在您的情況下,切換應用程序UI框架不是一個選項。 您必須弄清楚如何優化下拉列表等數據的加載。 這些數據經常變化嗎? 你可以在應用程序的某個地方緩存它嗎? 如果你每次都必須加載它們,你能否只是獲取顯示字符串而不是整個對象?

如果設置第一個結果和最大結果數,Hibernate將只從數據庫中檢索這些條目。 如果這很慢,請將max results設置為1並啟用SQL日志記錄以查看還加載了哪些關聯。

Hibernate還支持多個緩存:*第一級緩存:僅在一個Hibernate會話期間使用,通常對應於一個事務*二級緩存:用於會話/事務邊界,但大多數只能通過id方法查找*查詢緩存:如果啟用Hibernate將首先從那里查找查詢結果。 但是,查詢在HQL和參數方面必須相同,因此每個頁面可能會從DB加載一次然后被緩存。 (有關詳細信息,請查看此處: http//docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-querycache

請注意,緩存需要堆內存,並且根據實體的大小,緩存300萬個實體可能會導致巨大的內存損失,從而增加垃圾收集,這將再次影響性能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM