小编典典

使用HQL进行休眠分页

hibernate

细节

来自应用程序的HQL查询:

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

查询返回300万条记录,而对于分页,我们仅设置了其中的50条记录,分页页面的运行速度非常慢,因为每次刷新时,我们都调用查询来获取300万条记录,而其中只有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 | 桌子| 类型 可能的钥匙| 关键 key_len | 参考| 行| 过滤 额外|
 | 1 | 简单 getrequest0_ | 参考| TR_KIND_ID | TR_KIND_ID | 6 | const | 1703018 | 100.00 | 在哪里使用

附加信息:在50条记录的限制下使用和​​不使用order by子句的查询运行时间


如果我运行query with order子句,则查询花费 0.0012s 的设置LIMIT 50without order子句,相同的查询花费 0.0032s的sameLIMIT 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个结果,所以现在剩下300万条记录,在第二次调用此查询时,我们再次访问数据库并获得300万条记录并将其存储在内存中,然后在c处再次设置50条记录并继续执行上。

这个问题对我来说尚不明确,因此,如果有人可以提供清晰详细的解释,说明它的工作方式以及解决该问题的最佳方法,将不胜感激。

更新资料

事实证明,问题与页面上的记录显示无关,但是我在该页面上进行了过滤,并且在每个请求上都再次从数据库中获取所有下拉值,并且其中存在一些时髦的事情导致页面加载时间增加。

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


阅读 222

收藏
2020-06-20

共1个答案

小编典典

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

编辑1/26:现在已经弄清了具体问题,我将尝试更具体地回答。

  1. 每次执行这样的查询时,Hibernate都会进入数据库。甚至还会将会话中的所有新/更新数据刷新到磁盘。如果这是您的情况,则此行为可能会导致速度变慢。

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

您的查询运行时间似乎在毫秒级范围内。这通常与将数据存储在磁盘上的关系数据库一样好。因此,您可能需要评估您是否确实存在性能问题。

编辑1/27:好的。看起来好像页面的总体设计中存在问题。我使用AJAX已有大约7年了,因此在浏览表格的页面时,我通常不必等待筛选UI控件重绘。我想,切换应用程序UI框架不是您的选择。您必须找出如何优化下拉列表等数据的加载。此数据是否经常更改?您可以将其缓存在应用程序中的某个位置吗?如果您必须每次都加载它们,是否可以只获取显示字符串而不是整个对象而摆脱困境?

2020-06-20