NHibernate 与 SQL Server 分页

发布于 2024-08-09 01:07:54 字数 778 浏览 8 评论 0原文

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

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

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

我已经验证,使用 SQLite 数据库 NHibernate 可以利用 OFFSET 和 < code>LIMIT 关键字在数据库级别过滤结果。我知道 SQL Server 2000 中没有与 OFFSET 关键字和 Oracle 的 ROWNUM 等效的关键字,但是有什么解决方法吗? SQL Server 2005/2008 怎么样?

When using SetFirstResult(start) and SetMaxResults(count) methods to implement paging I've noticed that the generated query only does a select top count * from some_table and it does not take the start parameter into account or at least not at the database level. It seems that if I instruct NHibernate to execute the following query:

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

105 records will transit between the database server and the application which will take care to strip the first 100 records. With tables containing many rows this could be a problem.

I've verified that with an SQLite database NHibernate takes advantage of the OFFSET and LIMIT keywords to filter results at the database level. I am aware that there's no equivalent of the OFFSET keyword and Oracle's ROWNUM in SQL Server 2000 but is there any workaround? How about SQL Server 2005/2008?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

挽手叙旧 2024-08-16 01:07:54

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

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

T-SQL, the variant of the SQL language which Microsoft SQL Server uses, does not have a limit clause. It has a select top {...} modifier which you see NHibernate taking advantage of with SQL Server 2000.

With SQL Server 2005, Microsoft introduced the Row_Number() over (order by {...}) function which can be used as a replacement to the limit clause, and you can see NHibernate taking advantage of that with SQL Server 2005/2008.

A query for SQLite might look like

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

while a similar query for SQL Server 2005 might look like

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]

or, using Common Table Expressions, it might look like

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]

There is a way to do it in SQL Server 2000 as well

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]
-柠檬树下少年和吉他 2024-08-16 01:07:54

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

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

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


Nhibernate is smart enough to optimize query. If you select first 10 rows it will use TOP statement. If you select not first rows then it will use RowNum.

In sql 2000 there is no RowNum function, that's why it is impossible with usual query to select required number of rows. For sql 2000 as I know for such an optimization views were used.

In sql 2005/2008 query will select only required rows.


~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文