2009-10-30 78 views
13

当使用SetFirstResult(start)SetMaxResults(count)方法来实现分页我发现生成的查询仅做了select top count * from some_table,它不走start参数在内,或者至少不是在数据库级别。看来,如果我指导NHibernate的执行以下查询:NHibernate的分页与SQL Server

var users = session.CreateCriteria<User>() 
        .SetFirstResult(100) 
        .SetMaxResults(5) 
        .List<User>(); 

105记录将数据库服务器和会照顾剥离前100条记录的应用程序之间传输。对于包含许多行的表,这可能是一个问题。

我已验证使用SQLite数据库NHibernate利用OFFSETLIMIT关键字来筛选数据库级别的结果。我知道在SQL Server 2000中没有关于OFFSET关键字和Oracle的ROWNUM的等价物,但有没有解决方法? SQL Server 2005/2008如何?

回答

16

T-SQL是Microsoft SQL Server使用的SQL语言的变体,没有limit子句。它有一个select top {...}修改,你看到的NHibernate趁着与SQL Server 2000

在SQL Server 2005,微软推出了Row_Number() over (order by {...})功能,可以作为一个替代的limit条款,你可以看到NHibernate的利用与SQL Server 2005/2008相比。

一种SQLite的查询可能看起来像

select c.[ID], c.[Name] 
from [Codes] c 
where c.[Key] = 'abcdef' 
order by c.[Order] 
limit 20 offset 40 

而对于SQL Server 2005的一个类似的查询可能看起来像

select c.[ID], c.[Name] 
from (
    select c.[ID], c.[Name], c.[Order] 
     , [!RowNum] = Row_Number() over (order by c.[Order]) 
    from [Codes] c 
    where c.[Key] = 'abcdef' 
) c 
where c.[!RowNum] > 40 and c.[!RowNum] <= 60 
order by c.[Order] 

,或者使用公用表表达式,它可能看起来像

with 
    [Source] as (
     select c.[ID], c.[Name], c.[Order] 
      , [!RowNum] = Row_Number() over (order by c.[Order]) 
     from [Codes] c 
     where c.[Key] = 'abcdef' 
    ) 
select c.[ID], c.[Name] 
from [Source] c 
where c.[!RowNum] > 40 and c.[!RowNum] <= 60 
order by c.[Order] 

还有一种方法可以在SQL Server 2000中执行它以及

select c.[ID], c.[Name] 
from (
    select top 20 c.[ID], c.[Name], c.[Order] 
    from (
     select top 60 c.[ID], c.[Name], c.[Order] 
     from [Codes] c 
     where c.[Key] = 'abcdef' 
     order by c.[Order] 
    ) c 
    order by c.[Order] desc 
) c 
order by c.[Order] 
+0

很好的答案@Justice。谢谢你的时间。 – 2009-10-31 15:01:53

4

Nhibernate足够智能优化查询。如果您选择前10行,它将使用TOP语句。如果你不选择第一行,那么它将使用RowNum

在sql 2000中没有RowNum函数,这就是为什么用普通查询无法选择所需的行数的原因。对于我所知道的sql 2000,使用了这样的优化视图。

在sql 2005/2008查询中将只选择需要的行。


+3

我已经验证,与SQL 2005/2008 NHibernate使用'row_number()'函数。看来,与SQL 2000我不得不写视图或存储过程来实现相同的效果。 – 2009-10-31 14:51:35