使用SQL Server进行NHibernate分页

Dar*_*rov 13 nhibernate paging sql-server-2000

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

var users = session.CreateCriteria<User>()
                   .SetFirstResult(100)
                   .SetMaxResults(5)
                   .List<User>();
Run Code Online (Sandbox Code Playgroud)

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

我已经验证了使用SQLite数据库NHibernate利用OFFSETLIMIT关键字来过滤数据库级别的结果.我知道在SQL Server 2000中没有等效的OFFSET关键字和Oracle ROWNUM,但有没有解决方法?SQL Server 2005/2008怎么样?

yfe*_*lum 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的优势.

SQLite的查询可能看起来像

select c.[ID], c.[Name]
from [Codes] c
where c.[Key] = 'abcdef'
order by c.[Order]
limit 20 offset 40
Run Code Online (Sandbox Code Playgroud)

虽然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]
Run Code Online (Sandbox Code Playgroud)

或者,使用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]
Run Code Online (Sandbox Code Playgroud)

有一种方法可以在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]
Run Code Online (Sandbox Code Playgroud)


Sly*_*Sly 5

Nhibernate 足够聪明,可以优化查询。如果您选择前 10 行,它将使用TOP语句。如果您选择的不是第一行,那么它将使用RowNum.

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

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


  • 我已经验证了 sql 2005/2008 NHibernate 使用 `row_number()` 函数。看来使用sql 2000我必须编写视图或存储过程才能达到相同的效果。 (3认同)