0

現在、VS-Profiling ツールを使用して .net アプリケーションを最適化しようとしています。

非常に頻繁に呼び出される 1 つの関数には、次のコードが含まれています。

if (someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Count() == 0)
{
    lastPosition = 0;
}
else
{
    lastPosition = someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position).Cast<int>().First();
}

私はこのようなものに変更しました:

var relevantEntities = someObjectContext.someObjectSet.Where(i => i.PNT_ATT_ID == tmp_ATT_ID).OrderByDescending(i => i.Position).Select(i => i.Position);
if (relevantEntities.Count() == 0)
{
    lastPosition = 0;
}
else
{
    lastPosition = relevantEntities.Cast<int>().First();
}

クエリが 2 回実行されたことにコンパイラが気付き、結果をキャッシュするかどうかわからなかったので、変更によってメソッドが少し高速化されることを期待していました。

驚いたことに、メソッドの実行時間 (包括的サンプリングの数) は減少していませんが、9% も増加しています (プロファイラーによると)。

誰かがなぜこれが起こっているのか説明できますか?

4

2 に答える 2

3

コンパイラがクエリが 2 回実行されたことを認識して結果をキャッシュするかどうかわからなかったので、変更によってメソッドが少し高速化されることを期待していました。

ならない。実際、それはできません。データベースは、2 つのクエリに対して同じ結果を返さない場合があります。最初のクエリの後、2 番目のクエリの前に、結果が追加または削除される可能性は十分にあります。(このコードを非効率にするだけでなく、それが発生した場合に破損する可能性があります。)結果が異なる可能性があることを知って、2 つのクエリを実行することは完全に可能であるため、クエリの結果再実行されないことが重要です。使用済み。

ここで重要な点は、遅延実行の考え方です。 relevantEntities クエリの結果ではなく、クエリそのものです。が ( 、、ループIQueryableなどのメソッドによって) 反復されるまでデータベースがクエリされません。クエリを反復するたびに、データベースに対して別のクエリが実行されます。CountFirstforeach

あなたの場合、これを行うことができます:

var lastPosition = someObjectContext.someObjectSet
    .Where(i => i.PNT_ATT_ID == tmp_ATT_ID)
    .OrderByDescending(i => i.Position)
    .Select(i => i.Position)
    .Cast<int>()
    .FirstOrDefault();

これは、an のデフォルト値が 0 であるという事実を利用していますint。これは、以前に一致しなかった場合に値を設定していたものです。

これは機能的にはあなたのものと同じクエリであることに注意してください.2回実行するのを避けるだけです. さらに優れたクエリは、lazyberezovskyMaxによって提案されたクエリであり、最初のクエリを注文して取得するのではなく、活用しました。その列にインデックスがある場合、大きな違いはありませんが、インデックスがない場合、順序付けははるかに高価になります。

于 2013-06-19T15:00:11.683 に答える