2009-10-30 18 views
13

Wenn SetFirstResult(start) und SetMaxResults(count) Methoden Paging zu implementieren ich bemerkt habe, dass die erzeugte Abfrage nur ein select top count * from some_table tut und es nimmt nicht die start Parameter berücksichtigt oder zumindest nicht auf Datenbankebene. Es scheint, dass, wenn ich anweisen NHibernate die folgende Abfrage ausführen:NHibernate Paging mit SQL Server

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

105 Datensätze Transit zwischen dem Datenbankserver und die Anwendung, die darauf achten, werden die ersten 100 Datensätze strippen. Bei Tabellen mit vielen Zeilen könnte dies ein Problem sein.

Ich habe überprüft, dass mit einer SQLite Datenbank NHibernate die OFFSET und LIMIT Schlüsselwörter nutzt, um Ergebnisse auf Datenbankebene zu filtern. Mir ist bewusst, dass es in SQL Server 2000 kein Äquivalent für das Schlüsselwort OFFSET und Oracles ROWNUM gibt, aber gibt es eine Problemumgehung? Wie wäre es mit SQL Server 2005/2008?

Antwort

16

T-SQL, die Variante der SQL-Sprache, die Microsoft SQL Server verwendet, hat keine limit Klausel. Es hat einen select top {...} Modifikator, die Sie NHibernate Vorteil mit SQL Server unter siehe 2000.

Mit SQL Server 2005 hat Microsoft die Row_Number() over (order by {...}) Funktion, die als Ersatz für die limit Klausel verwendet werden kann, und Sie können sehen NHibernate unter Ausnutzung davon mit SQL Server 2005/2008.

Eine Abfrage für SQLite wie

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

aussehen könnte, während eine ähnliche Abfrage für SQL Server 2005 wie

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] 

oder aussehen könnte, Common Table Expressions verwenden, könnte es wie

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

Es gibt eine Möglichkeit, dies auch in SQL Server 2000

zu tun
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

Große Antwort @Justice. Vielen Dank für Ihre Zeit. –

4

Nhibernate ist intelligent genug, um die Abfrage zu optimieren. Wenn Sie die ersten 10 Zeilen auswählen, wird TOP Anweisung verwendet. Wenn Sie keine ersten Zeilen auswählen, wird RowNum verwendet.

In Sql 2000 gibt es keine RowNum Funktion, deshalb ist es mit der üblichen Abfrage unmöglich, die erforderliche Anzahl von Zeilen auszuwählen. Für Sql 2000 wurden, wie ich für eine solche Optimierung weiß, Sichten verwendet.

In SQL 2005/2008 Abfrage wird nur die erforderlichen Zeilen auswählen.


+3

Ich habe überprüft, dass mit Sql 2005/2008 NHibernate die 'row_number()' Funktion verwendet. Es scheint, dass ich mit Sql 2000 Ansichten oder gespeicherte Prozeduren schreiben muss, um denselben Effekt zu erzielen. –