0

ac# プロジェクトの SQLite DB で NHibernate を使用しています。次のような一般的な一括データ処理メソッドがあります。

    private void DataProcess<Tobj>(int pageSize, Expression<Func<Tobj, bool>> whereClause,
        Action<Tobj, ISession> dataProcessingCallback) where Tobj : IModelBase
    {
        int offset = 0;
        bool moreToGet = true;

        while (moreToGet)
        {
            DataAccess((ISession session) =>
            {
                IEnumerable<Tobj> result = session.Query<Tobj>().Where(whereClause);
                List<Tobj> data = result.Skip(offset)
                    .Take(pageSize)
                    .ToList();
                foreach (Tobj item in data) { dataProcessingCallback(item, session); }

                if (data.Count == pageSize) { offset += pageSize; }
                else { moreToGet = false; }
            });
        }
    }

(DataAccess メソッドは、操作するセッション オブジェクトを提供し、トランザクションを処理します。)

周りを見渡すと、これは他のほとんどの linq ページング実装と非常によく似ているようです。彼らは一般的に .Skip().Take() を行います

私の問題は、大規模なデータ セット (私が見ているテスト ケースでは約 20 万行あります) の場合、result.Skip(offset).Take(pageSize).ToList を実行するのに AGES (デバッガーで約 20 秒) かかることです。 (); ライン。これは pageSize = 100 で、offset = 0 です。

私の理解では、遅延実行のため、必要になるまで SELECT は発生しません (この場合は .ToList())。この時点で、必要な行は関連する 100 行のみを選択する必要があることがわかります。

「データ」には予想される 100 行がありますが、システムが DB から 200k の奇数行をすべてフェッチし、コードでページングを実行したように見えます。

私のLINQ/NHibernateの理解は間違っていますか? もしそうなら、基準 API で次のようなことをする必要があると思います: NHibernate Paging performance (Better option)

4

1 に答える 1

1

次の行を見てください。

IEnumerable<Tobj> result = session.Query<Tobj>().Where(whereClause);

IEnumerable<Tobj>フィールドを使用しているためSkip、を呼び出すと、Enumerable.Skipメソッドが呼び出されます。私はあなたが望むのはQueryable.Skip方法だと信じています。

代わりに、次のコード行を試してください。

IQueryable<Tobj> result = session.Query<Tobj>().Where(whereClause);

これにより、正しい拡張メソッドが確実に呼び出されます。

説明

このEnumerable.Skipメソッドは、ソース内の各エンティティをループし、IEnumerable<Tobj>N個の要素の後に結果を返します。NHibernateはデータが必要であることのみを認識しているため、これによりNHibernateはすべてのデータをメモリにロードします。

このQueryable.Skipメソッドは代わりに式ツリーを構築し、NHibernateが後でデータにアクセスするときにこれを処理できるようにします。その時点で、NHibernateは最初のNレコードをスキップすることを知っています。

ただし、注意してください。LINQプロバイダーが現在SkipandTakeメソッドをサポートしているかどうかはわかりません。

于 2012-12-11T13:04:03.300 に答える