使用SQL Server进行NHibernate分页

时间:2009-10-30 19:04:30

标签: nhibernate sql-server-2000 paging

使用SetFirstResult(start)SetMaxResults(count)方法实现分页时,我注意到生成的查询只执行select top count * from some_table并且不考虑start参数或至少不在数据库级别。看来如果我指示NHibernate执行以下查询:

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怎么样?

2 个答案:

答案 0 :(得分:16)

T-SQL是Microsoft SQL Server使用的SQL语言的变体,它没有limit子句。它有一个select top {...}修饰符,你可以看到NHibernate利用了SQL Server 2000。

使用SQL Server 2005,Microsoft引入了Row_Number() over (order by {...})函数,可用作limit子句的替代,您可以看到NHibernate利用SQL Server 2005/2008的优势。 / p>

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]

或使用Common Table Expressions,它可能看起来像

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]

答案 1 :(得分:4)

Nhibernate非常聪明,可以优化查询。如果您选择前10行,它将使用TOP语句。如果您不选择第一行,则会使用RowNum

在sql 2000中没有RowNum函数,这就是为什么通常的查询不可能选择所需的行数。对于sql 2000,因为我知道这样的优化视图被使用。

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