使用HQL进行Hibernate分页

Rac*_*hel 4 java performance pagination hibernate 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);
Run Code Online (Sandbox Code Playgroud)

查询返回300万条记录,对于分页,我们只设置了50条记录,分页页面非常慢,因为在每次刷新时我们都会调用查询来获取3百万条记录,而我们只设置50条记录.

我的主要问题是

HQL是否总是进入并命中数据库,或者它是否会进入会话或内存以查找数据,如果它每次都进入数据库并获得结果集那么从性能的角度来看它是非常合适的,什么是最好的解决方案来改进它?

在hibernate中使用HQL有一种方法可以查询数据库并首先获取50条记录,然后根据用户的要求获取其他记录.这个挑战真的让应用程序陷入困境,那么解决这个问题的最佳方法是什么呢?

在日志中生成的HQL查询

from com.delta.dao.RequestDao r order by r.id desc
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

以下是查询的解释计划:


 | 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子句然后查询需要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);
    
    Run Code Online (Sandbox Code Playgroud)

在a,我们从数据库获得结果并将其存储在内存中,或者如果没有,并且此时我们在结果集中有300万个结果,然后在b和c我们设置偏移值并限制在页面上我们会这样,这是真的吗?只看到50个结果,所以现在剩下3百万条记录,在我们第二次调用这个查询时,我们再次进入数据库并获取300万条记录并将它们放入内存然后在c再次设置50条记录并继续上.

这个问题对我来说并不清楚,因此如果有人能够提供明确而详细的解释,说明这是如何工作以及什么是这个问题的最佳解决方案,我将非常感激.

更新

事实证明,问题与页面上的记录显示无关,但我在该页面上有过滤器,并且每次请求都会从数据库中再次获取所有下拉值,并且在那里有一些时髦的事情发生在那里导致页面加载时间增加.

我正在对数据库进行多个嵌套的hibernate查询并获得结果,这个问题的最佳解决方案是什么?

Ola*_*laf 5

您的查询告诉数据库对所有满足WHERE子句的记录进行排序.它有可能在返回前50之前对数百万条记录进行排序.

编辑1/26:现在澄清了具体问题,我将尝试更具体地回答.

  1. 每次执行这样的查询时,Hibernate都会进入数据库.更重要的是,它会将会话中的所有新/更新数据刷新到磁盘.如果这是您的情况,此行为可能会导致缓慢.

  2. 使用Hibernate查询API通常在大多数情况下都能很好地运行,并且与各种各样的数据库平台兼容.如果您真的担心从数据访问层中挤出最后一滴性能,您可以编写自己的本机SQL查询来选择前50个结果.但是一旦你这样做,你几乎肯定会失去数据库独立性.因此,评估您的成本与收益.

您的查询运行时间似乎在单毫秒范围内.这通常与在磁盘上存储数据的关系数据库一样好.所以你可能想评估一下你是否确实遇到了性能问题.

编辑1/27:好的.它看起来像页面整体设计中的问题.我在过去7年左右一直在使用AJAX,所以我通常不必等待过滤UI控件在浏览表格时重绘.我想,在您的情况下,切换应用程序UI框架不是一个选项.您必须弄清楚如何优化下拉列表等数据的加载.这些数据经常变化吗?你可以在应用程序的某个地方缓存它吗?如果你每次都必须加载它们,你能否只是获取显示字符串而不是整个对象?