質問

SetFirstResult(start)および SetMaxResults(count)メソッドを使用してページングを実装すると、生成されたクエリは select top count *のみを実行することに気付きました。 some_table から取得し、 start パラメータを考慮しないか、少なくともデータベースレベルでは考慮しません。 NHibernateに次のクエリを実行するように指示した場合:

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

105レコードはデータベースサーバーとアプリケーションの間を通過し、最初の100レコードを削除するように注意します。多くの行を含むテーブルでは、これが問題になる可能性があります。

SQLite データベースでNHibernateが OFFSET および LIMIT キーワードを使用して、データベースレベルで結果をフィルタリングします。 SQL Server 2000には OFFSET キーワードとOracleの ROWNUM に相当するものがないことを知っていますが、回避策はありますか? SQL Server 2005/2008はどうですか?

役に立ちましたか?

解決

Microsoft SQL Serverが使用するSQL言語の変形である

T-SQLには、 limit 句がありません。 NHibernateがSQL Server 2000を利用していることがわかる select top {...} 修飾子があります。

SQL Server 2005で、Microsoftは limit 句の代わりとして使用できる Row_Number()over(order by {...})関数を導入しました、そして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]

他のヒント

Nhibernateはクエリを最適化するのに十分スマートです。最初の10行を選択すると、 TOP ステートメントが使用されます。最初の行以外を選択すると、 RowNum が使用されます。

SQL 2000には RowNum 関数はありません。そのため、通常のクエリでは必要な行数を選択することはできません。私が知っているようなSQL 2000では、そのような最適化ビューが使用されました。

SQL 2005/2008のクエリでは、必要な行のみが選択されます。


ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top