1

複雑な Entity Framework クエリがあります。私のパフォーマンスのボトルネックは、実際にデータベースをクエリすることではなく、IQueryable をクエリ テキストに変換することです。

私のコードは次のようなものです:

var query = context.Hands.Where(...)
if(x)
    query = query.where(...)
....
var result = query.OrderBy(...)
var page = result.skip(500 * pageNumber).Take(500).ToList(); //loong time here, even before calling the DB

do
{
    foreach(var h in page) { ... }

    pageNumber += 1;
    page = result.skip(500 * pageNumber).Take(500).ToList(); //same here
}
while(y)

私に何ができる?私は(SQLiteで)DbContextを使用しているため、プリコンパイルされたクエリを使用できません(それでも、このようなクエリ構築アルゴリズムでは面倒です)。

基本的に必要なのは、「ページ」クエリをキャッシュし、「スキップ」パラメーターと「取得」パラメーターのみを変更することです。毎回ゼロから再コンパイルする必要はありません。

4

1 に答える 1

4

あなたの前提は間違っています。ToListクエリの最後に呼び出しがあるため、指定したデータベースクエリを実行して、リストを作成します。もう実行を延期していません。時間がかかるのはそのためです。クエリの作成に長い時間を費やしていません。データベースに移動して実際に実行するのに長い時間がかかります。

それが役立つ場合は、次の方法を使用してページネーションを行うことができます。次のページを要求するまで、各ページのフェッチを延期します。

public static IEnumerable<IEnumerable<T>> Paginate<T>(
    this IQueryable<T> query, int pagesize)
{
    int pageNumber = 0;

    var page = query.Take(pagesize).ToList();
    while (page.Any())
    {
        yield return page;
        pageNumber++;
        page = query.Skip(pageNumber * pagesize)
            .Take(pagesize)
            .ToList();
    }
}

したがって、このコードがある場合:

var result = query.OrderBy(...);
var pages = result.Paginate();//still haven't hit the database

//each iteration of this loop will go query the DB once to get that page
foreach(var page in pages)
{
    //use page
}

すべてのページをクエリとして取得したい場合IEnumerable<IQueryable<T>>(つまり、データベースに送信する前にさらにフィルターを追加できることを意味します)、主な問題は、ページ数がわからないことです。なれ。最後のページかどうかを知るには、特定のクエリを実際に実行する必要があります。このコードのように、各ページをフェッチするか、最初にページ化されていないクエリの数をクエリする必要があります (これは、他の方法で必要になるよりも 1 つ多い DB クエリを意味します)。それを行うと、次のようになります。

public static IEnumerable<IQueryable<T>> Paginate<T>(
    this IQueryable<T> query, int pagesize)
{
    //note that this is hitting the DB
    int numPages = (int)Math.Ceiling(query.Count() / (double)pagesize);

    for (int i = 0; i < numPages; i++)
    {
        var page = query.Skip(i * pagesize)
                .Take(pagesize);
        yield return page;
    }
}
于 2013-07-03T14:45:55.213 に答える