1

私は過去数日間、次のクエリを最適化する方法を見つけようとしていましたが、あまり運がありませんでした。現在、私のテストデータベースはネストされたデータがほとんどない約300レコードを返していますが、実行に4〜5秒かかり、LINQによって生成されるSQLは非常に長いです(ここに含めるには長すぎます)。任意の提案をいただければ幸いです。

このクエリを要約すると、現在のステータスを持つクライアントリストのやや平坦化された「スナップショット」を返そうとしています。パーティーには、ロール(ASPNETロールプロバイダー)を持つ1つ以上のクライアントが含まれ、Journalはパーティー内のすべてのクライアントの最後の1つのジャーナルエントリを返します。同じことがTaskとLastLoginDateにも当てはまります。したがって、OrderBy関数とFirstOrDefault関数です。

Guid userID = 'some user ID'
var parties = Parties.Where(p => p.BrokerID == userID).Select(p => new
{
ID = p.ID,
Title = p.Title,
Goal = p.Goal,
Groups = p.Groups,
IsBuyer = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer")),
IsSeller = p.Clients.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "seller")),
Journal = p.Clients.SelectMany(c => c.Journals).OrderByDescending(j => j.OccuredOn).Select(j=> new 
    { 
        ID = j.ID,
        Title = j.Title,
        OccurredOn = j.OccuredOn,
        SubCatTitle = j.JournalSubcategory.Title
    }).FirstOrDefault(),
LastLoginDate = p.Clients.OrderByDescending(c=>c.LastLoginDate).Select(c=>c.LastLoginDate).FirstOrDefault(),
MarketingPlanCount = p.Clients.SelectMany(c => c.MarketingPlans).Count(),
Task = p.Tasks.Where(t=>t.DueDate != null && t.DueDate > DateTime.Now).OrderBy(t=>t.DueDate).Select(t=> new 
    {
        ID = t.TaskID,
        DueDate = t.DueDate,
        Title = t.Title
    }).FirstOrDefault(),
Clients = p.Clients.Select(c => new
    {
        ID = c.ID,
        FirstName = c.FirstName,
        MiddleName = c.MiddleName,
        LastName = c.LastName,
        Email = c.Email,
        LastLogin = c.LastLoginDate
    })
}).OrderBy(p => p.Title).ToList()
4

1 に答える 1

0

SQLを投稿すると、いくつかの手がかりが得られると思います。予測の前後にあるOrderByの順序のような小さなものが、大きな違いを生む可能性があるからです。

ただし、別のクエリでクライアントを抽出してみてください。これにより、クエリが単純化される可能性があります。次に、投影する前にジャーナルやタスクなどの他のテーブルを含めて、これがクエリにどのように影響するかを確認します。

    //正確なクエリが何であるかわからない場合は、ToList()を使用してプロジェクトを投影します
    var projects = GetClientsForParty();

    var party = Parties.Include( "Journal")。Include( "Tasks")
          .Where(p => p.BrokerID == userID).Select(p => {

    ...。
    //次にメモリ内クライアントを使用します
    IsBuyer = projects.Any(c => c.RolesInUser.Any(r => r.Role.LoweredName == "buyer"))、
    ..。
    }
    )。

いずれの場合も、 EFプロファイラーをインストールして、クエリがどのように影響を受けるかを確認してください。EFは驚くほど静かになります。投影の前にOrderByを配置するようなもので、これらすべてのFirstOrDefaultまたはSingleOrDefaultでも同じですが、これらはすべて大きな影響を与える可能性があります。

そして、基本に戻り、LoweredRoleNameで検索している場合は、クエリが高速になるようにインデックスが付けられていることを確認します(ただし、EFはクエリを実行しているため、カバーインデックスを使用しなくなる可能性があるため、役に立たない可能性があります。他の多くの列)。

また、これはデータを表示するためのクエリであるため(データを変更することはありません)、エンティティトラッキングをオフにすることを忘れないでください。これにより、パフォーマンスも向上します。

そして最後に、SQLクエリをいつでも直接記述して、匿名型ではなくViewModelに投影できることを忘れないでください(とにかく良い習慣だと思います)。そのため、目的のフラットビューを含むPartyViewModelというクラスを作成します。 、手作りのSQLで使用します

//作成した最適化されたSQLクエリを使用するか、ストアドプロシージャを呼び出します
db.Database.SQLQuery( "select * from .... join .... on");

私はEFに関するこれらの問題についてブログ記事を書いています。投稿はまだ完了していませんが、全体として、辛抱強く、これらのトリックのいくつかを使用してその効果を観察(および測定)すると、目的の結果に到達します。

于 2012-10-07T18:28:18.213 に答える