Hibernate(/ JPA)服务器端分页和MS SQL Server

时间:2012-03-26 08:23:36

标签: sql-server sql-server-2008 hibernate jpa orm

我使用 hibernate / JPA实施服务器端数据分页,底层数据库是 MS SQL Server 2008。

SQL生成如下:

criteria.setFirstResult(pagingParams.getDisplayStart())
.setMaxResults(pagingParams.getDisplayLength());

(主要工作在于创建适当的过滤器/排序,但这与此无关)

我正在观察的是以下SQL:

page (0-20):
select top 20 this_.id as id11_9_,...

page (20-40):
select top 40 this_.id as id11_9_,... 

page (40-60):
select top 60 this_.id as id11_9_,... 

......等等。

显然,如果基础结果集太大而且(b)与分页没什么关系,那么(a)将遇到严重问题: - (

有同样问题的人?

更新:好像是Tiber的Row_Number()函数的NHibernate(Hibernate的.NET实现)takes advantage。遗憾的是Hibernate没有...

3 个答案:

答案 0 :(得分:8)

有点迟到的回复,但它可能会有所帮助,所以我会发布它。有完全相同的问题和头痛来追踪它。解决方案是使用Hibernate 4.3.0中包含的org.hibernate.dialect.SQLServer2012Dialect。生成的查询变为(粘贴没有列名和别名的真实Hibernate转储):

WITH query 
     AS (SELECT inner_query.*, 
                Row_number() 
                  OVER ( 
                    ORDER BY CURRENT_TIMESTAMP) AS __hibernate_row_nr__ 
         FROM   (SELECT TOP(?) <COLUMN_NAMES> AS <ALIASES>
FROM <TABLE_NAME>
) inner_query) 
SELECT <ALIASES>
FROM   query 
WHERE  __hibernate_row_nr__ >= ? 
       AND __hibernate_row_nr__ < ?

注意内部查询和Row_number()函数的用法。他们终于解决了!

答案 1 :(得分:4)

我们也观察到Hibernate 3.3与hibernate.dialect=org.hibernate.dialect.SQLServerDialect(使用SQL Server 2008 R2)的相同行为。

我的印象是,当使用Hibernate&gt; = 3.5,将hibernate.dialect设置为org.hibernate.dialect.SQLServer2005Dialectorg.hibernate.dialect.SQLServer2008Dialect,使用SQL Server&gt; = 2005时,此性能问题就消失了可能还有SQL Server驱动程序JDBC&gt; = 3.0。

备用上述展示的其他链接:

答案 2 :(得分:2)

这是因为MSSQL没有为此版本提供真正的分页实现。确实有可能在Row_Number()中使用内部查询,但就像你提到的那样,Hibernate不使用它。

我发现某些人修改了SQLServer2008Dialect.java以使其使用Row_Number()。 follow this link

编辑:(我注意到这些文件的来源不再可用)

在MSSQL2012中,应解决此问题,因为它们实现了分页功能。剩下的唯一问题是这个版本的MSSQL没有特定的方言。他们建议使用旧的(MSSQL2008),但这会导致相同的分页问题。