简体   繁体   English

使用HQL进行Hibernate分页

[英]Hibernate Pagination using HQL

Hibernate Pagination Issue Hibernate分页问题

I have an issue which is related to Hibernate Pagination and to some extent this has been explained in 我有一个与Hibernate分页有关的问题,并且在某种程度上已经解释了这个问题

Mysql Pagination Optimization Mysql分页优化

Using Hibernate's ScrollableResults to slowly read 90 million records 使用Hibernate的ScrollableResults慢慢读取9000万条记录

Hibernate - HQL pagination Hibernate - HQL分页

Issues with Pagination and Sorting 分页和排序的问题

Hibernate Row Pagination Hibernate Row Pagination

Details 细节

HQL Query from Application: 来自应用程序的HQL查询:

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

Query returns 3 million records and for pagination we are setting only 50 of those records, pagination page is very slow because on every refresh we are calling the query which get 3 millions records and out of those we only set 50 records. 查询返回300万条记录,对于分页,我们只设置了50条记录,分页页面非常慢,因为在每次刷新时我们都会调用查询来获取3百万条记录,而我们只设置50条记录。

My main question is 我的主要问题是

Does HQL always goes and hits database or does it go and hit session or memory to look for the data and if it goes everytime to hit database and get resultset then it is very proper from performance point of view, what would be best solutions to improve it? HQL是否总是进入并命中数据库,或者它是否会进入会话或内存以查找数据,如果它每次都进入数据库并获得结果集那么从性能的角度来看它是非常合适的,什么是最好的解决方案来改进它?

Using HQL in hibernate is there a way we can query database and get only 50 records out first and then get other records as required by the user. 在hibernate中使用HQL有一种方法可以查询数据库并首先获取50条记录,然后根据用户的要求获取其他记录。 This challenge is really bogging down application and so what would be best way to solve this problem? 这个挑战真的让应用程序陷入困境,那么解决这个问题的最佳方法是什么呢?

HQL Query generated in logs 在日志中生成的HQL查询

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

Hibernate Generated Query 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

Here is the Explain Plan for the query: 以下是查询的解释计划


| 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 |

Additional information: Query run time with and without order by clause on 50 records limit 附加信息:在50个记录限制上查询带有和不带order by子句的运行时间


If i run query with order clause then query takes 0.0012s with setting LIMIT 50 and without order clause, same query takes 0.0032s with same LIMIT 50 . 如果我with order子句运行查询with order那么查询需要0.0012s并设置LIMIT 50without order子句,同一查询需要0.0032s且具有相同的LIMIT 50


Also how can we find if: 另外,我们如何找到:

  1. Particular HQL Query is hitting database and not cache or getting information from session? 特定的HQL查询是命中数据库而不是缓存或从会话中获取信息?
  2. Is it true that HQL Query will always go and hit database to get result out and Criteria would go and hit session or cache and get results from it? 是否真的HQL查询总是会命中数据库以获得结果,而Criteria会进入并点击会话或缓存并从中获取结果?
  3. Also in my below mentioned query: 另外在我下面提到的查询中:

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

at a, is it true that we get result from database and store it in memory or where if not and at this time we have 3 million results in result set and then at b and c we set offset value and limit so on page we would only see 50 results so now where are remaining 3 million records and on our second call to this query do we again go and hit database and get 3 million records and put them in memory and then at c again we set 50 records and go on an on. 在a,我们从数据库获得结果并将其存储在内存中,或者如果没有,并且此时我们在结果集中有300万个结果,然后在b和c我们设置偏移值并限制在页面上我们会这样,这是真的吗?只看到50个结果,所以现在剩下3百万条记录,在我们第二次调用这个查询时,我们再次进入数据库并获取300万条记录并将它们放入内存然后在c再次设置50条记录并继续上。

This issue is not clear to me and so would highly appreciate if someone can provide clear and detailed explanation as how this is working and what would be best solution for this problem. 这个问题对我来说并不清楚,因此如果有人能够提供明确而详细的解释,说明这是如何工作的,以及什么是解决这个问题的最佳解决方案,我们将非常感激。

Update 更新

As it turns out, issue am having is not related to display of records on the page but i have filter on that page and on every request am getting all drop down values again from database and there are some funky things going on in there that is causing rise in page load time. 事实证明,问题与页面上的记录显示无关,但我在该页面上有过滤器,并且每次请求都会从数据库中再次获取所有下拉值,并且在那里有一些时髦的事情发生在那里导致页面加载时间增加。

I am making multiple nested hibernate queries to database and getting results back, what would be an optimal solution for this problem? 我正在对数据库进行多个嵌套的hibernate查询并获得结果,这个问题的最佳解决方案是什么?

Your query tells database to sort all records that satisfy the WHERE clause. 您的查询告诉数据库对所有满足WHERE子句的记录进行排序。 It potentially may sort millions of records before returning you top 50. 它有可能在返回前50之前对数百万条记录进行排序。

EDIT 1/26: Now that the specific questions were clarified, I'll try to respond more specifically. 编辑1/26:现在澄清了具体问题,我将尝试更具体地回答。

  1. Every time you execute query like that, Hibernate goes to the database. 每次执行这样的查询时,Hibernate都会进入数据库。 Even more, it would flush all new/updated data in the session to disk. 更重要的是,它会将会话中的所有新/更新数据刷新到磁盘。 If this is your situation, this behavior might contribute to the slowness. 如果这是您的情况,此行为可能会导致缓慢。

  2. Using Hibernate Query API usually performs quite well in most situations and is compatible with a broad variety of the database platforms. 使用Hibernate查询API通常在大多数情况下都能很好地运行,并且与各种各样的数据库平台兼容。 If you are really concerned about squeezing last drop of performance out of your data access layer, you can write your own native SQL query to select top 50 results. 如果您真的担心从数据访问层中挤出最后一滴性能,您可以编写自己的本机SQL查询来选择前50个结果。 But as soon as you do that, you'll almost certainly loose database independence. 但是一旦你这样做,你几乎肯定会失去数据库独立性。 So, evaluate your costs vs. benefits. 因此,评估您的成本与收益。

Your query run times appear to be in the single milliseconds range. 您的查询运行时间似乎在单毫秒范围内。 This is usually as good as it gets with the relational databases that store data on disk. 这通常与在磁盘上存储数据的关系数据库一样好。 So you might want to evaluate whether you indeed have a performance problem. 所以你可能想评估一下你是否确实遇到了性能问题。

EDIT 1/27: OK. 编辑1/27:好的。 It looks like the problem in the overall design of the page. 它看起来像页面整体设计中的问题。 I had been using AJAX for last 7 years or so, so I don't usually have to wait for the filtering UI controls to redraw when going through pages of a table. 我在过去7年左右一直在使用AJAX,所以我通常不必等待过滤UI控件在浏览表格时重绘。 I guess, switching application UI frameworks is not an option in your case. 我想,在您的情况下,切换应用程序UI框架不是一个选项。 You have to figure out how to optimize loading of the data for the dropdowns and such. 您必须弄清楚如何优化下拉列表等数据的加载。 Does this data change frequently? 这些数据经常变化吗? Can you cache it somewhere in the application? 你可以在应用程序的某个地方缓存它吗? If you have to load them every time, can you get away with just getting the display strings instead of entire objects? 如果你每次都必须加载它们,你能否只是获取显示字符串而不是整个对象?

If you set the first result and the maximum number of results Hibernate will only retrieve those entries from the database. 如果设置第一个结果和最大结果数,Hibernate将只从数据库中检索这些条目。 If that is slow, set max results to 1 and enable SQL logging to see which associations are loaded as well. 如果这很慢,请将max results设置为1并启用SQL日志记录以查看还加载了哪些关联。

Hibernate also supports several caches: * first level cache: will only be used during one Hibernate session which often corresponds to one transaction * second level cache: used over session/transaction boundaries, but mostly only by find by id methods * query cache: if enabled Hibernate will lookup the query results from there first. Hibernate还支持多个缓存:*第一级缓存:仅在一个Hibernate会话期间使用,通常对应于一个事务*二级缓存:用于会话/事务边界,但大多数只能通过id方法查找*查询缓存:如果启用Hibernate将首先从那里查找查询结果。 However, the query must be the same in terms of HQL and parameters so each page might be loaded from the DB once and then be cached. 但是,查询在HQL和参数方面必须相同,因此每个页面可能会从DB加载一次然后被缓存。 (For more information have a look here: http://docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-querycache ) (有关详细信息,请查看此处: http//docs.jboss.org/hibernate/core/3.5/reference/en/html/performance.html#performance-querycache

Please note that caching requires heap memory and depending on the size of your entities caching 3 million entities might result in a huge memory hit and thus increased garbage collection which would hit performance again. 请注意,缓存需要堆内存,并且根据实体的大小,缓存300万个实体可能会导致巨大的内存损失,从而增加垃圾收集,这将再次影响性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM