2009-10-30 79 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