2011-11-08 1 views
0

コンパイルされたクエリを使用して、一般的に実行されるlinqからエンティティへのクエリのパフォーマンスを向上させました。 1つのシナリオでは、私はそれを最も基本的な形式に煮詰めて、あらかじめコンパイルした後、ユーザー入力に基づいてwhere句を追加します。コンパイルされたクエリに連鎖するとパフォーマンス上の利点が失われます

この特定のケースでは、コンパイルされたクエリのパフォーマンス上の利点が失われているようです。なぜ誰かが説明できますか?

ここで私がやっているものの例です...

IEnumerable<Task> tasks = compiledQuery.Invoke(context, userId); 

if(status != null) 
{ 
    tasks = tasks.Where(x=x.Status == status); 
} 
if(category != null) 
{ 
    tasks = tasks.Where(x=x.Category == category); 
} 

return tasks; 

答えて

1

を無視する必要があることを示している私はそれが重要だと思いますEFでコンパイルされたクエリがどのように機能するかを理解する。

クエリを実行すると、エンティティフレームワークは、マッピングファイル(EDMXまたは最初のモデル定義)のヘルプを使用して式ツリーをSQLクエリにマップします。これは、複雑でパフォーマンスの高い作業です。

プリコンパイルではこれらのマッピング・フェーズの結果が格納されるので、次に問合せを実行するとSQLがすでに使用可能になり、現在のパラメータのみを設定する必要があります。

プリコンパイルされたクエリは、クエリを変更するとすぐにパフォーマンス上のメリットが失われるという問題があります。のは、以下のあなたが持っているとしましょう:

IQueryable query = GetCompiledQuery(); // => db.Tasks.Where(t => t.Id == myId); 
var notModifiedResult = query.ToList(); // Fast 
int ModifiedResult = query.Count(); // Slow 

を最初のクエリではEFが既にあなたのために生成されたSQLを持っており、すぐにこれを実行することができますので、あなたがプリコンパイルのすべての利点を持っています。 2番目のクエリは、SQLを再生成する必要があるため、プリコンパイルが失われます。

notModifiedResultでクエリを実行すると、SQLをデータベースに実行してメモリ内のすべての要素をフェッチしたため、これはLinq To Objectsになります。

しかし、コンパイルされたクエリをチェーンすることはできます(つまり、コンパイルされたクエリを別のコンパイル済みクエリで使用することができます)。

しかし、あなたのコードがコンパイルされたクエリの一連必要になります。 - デフォルト - ワンステータスとカテゴリの両方= nullを

- カテゴリ= nullの 1 - ステータス= nullの ワン!!!
1

は(注:私は年齢のための任意EF作業を行っていないし、それだけでポタリングした。これは、単なる情報に基づいた推測です。 。

IEnumerable<Task> tasks = compiledQuery.Invoke(context, userId); 

どれさらに問い合わせがないSQLで、.NETプロセス内で実行する必要があります、本当に)

これが犯人である可能性があります。 可能なの結果はすべてデータベースからフェッチし、ローカルでフィルタ処理する必要があります。代わりにこれを試してみてください:

IQueryable<Task> tasks = compiledQuery.Invoke(context, userId); 

(。それはもちろん、有効だと仮定)

0

コンパイルされたクエリは、パラメータのみを変更することができ、変更することはできません。ここでは、実際にクエリを実行して、結果をフィルタリングしています。

.Invoke(context, userId); // returns all the results 
.Where(....) // filters on that entire collection 

あなたはパラメータがすべての場合に含めることができるように、クエリを修正再表示するために巧妙な方法があるかどうかが、任意の効果を持つことはできません。私はコンパイルされたクエリを扱っていませんが、残念ですが、この作業は-1を "無視"値として使用しますか? SQLで

// bunch of code to define the compiled query part, copied from [msdn][1] 
(ctx, total) => from order in ctx.SalesOrderHeaders 
         where (total == -1 || order.TotalDue >= total) 
         select order); 

、あなたはどちらかの動的SQLを使用して、またはデフォルト値(またはnull)を有することにより、これを行うあなたは合格、そのパラメータが

select * from table t 
where 
    (@age = 0  or t.age = @age) and 
    (@weight is null or t.weight = @weight) 
関連する問題