19

Entity Framework を使用しており、name = "xyz" の製品が存在するかどうかを確認する必要があります ...

Any()、Exists()、または First() を使用できると思います。

このような状況に最適なオプションはどれですか? どれが最高のパフォーマンスを持っていますか?

ありがとうございました、

ミゲル

4

5 に答える 5

32

わかりました、私はこれについて検討するつもりはありませんでしたが、ディエゴの答えは物事を複雑にしているので、追加の説明が必要だと思います.

ほとんどの場合、.Any()より高速になります。下記は用例です。

Workflows.Where(w => w.Activities.Any())
Workflows.Where(w => w.Activities.Any(a => a.Title == "xyz"))

上記の 2 つの例では、Entity Framework が最適なクエリを生成します。.Any()呼び出しは述語の一部であり、Entity Framework はこれを適切に処理します。ただし、.Any()結果セットの一部の結果を次のようにすると:

Workflows.Select(w => w.Activities.Any(a => a.Title == "xyz"))

...突然、Entity Framework が 2 つのバージョンの条件を作成することを決定したため、クエリは実際に必要な作業の 2 倍の作業を行います。ただし、次のクエリはそれほど優れていません。

Workflows.Select(w => w.Activities.Count(a => a.Title == "xyz") > 0)

上記のクエリを指定すると、Entity Framework は引き続き 2 つのバージョンの条件を作成します。さらに、SQL Server で実際のカウントを行う必要があります。つまり、アイテムが見つかってもすぐに短絡することはありません。

ただし、これら 2 つのクエリを比較するだけの場合は、次のようになります。

  1. Activities.Any(a => a.Title == "xyz")
  2. Activities.Count(a => a.Title == "xyz") > 0

...どちらが速くなりますか? 場合によります。

最初のクエリは非効率的な二重条件クエリを生成します。つまり、最大で 2 倍の時間がかかります。

N2 番目のクエリは、データベースがテーブル内のすべてのアイテムをショートサーキットせずにチェックするように強制します。つまり、一致を見つける前に評価する必要があるアイテムの数によっては、必要以上に時間がかかる可能性があります。テーブルに 10,000 個の項目があるとします。

  • テーブル内に条件に一致する項目がない場合、このクエリは最初のクエリの約半分の時間で済みます。
  • テーブルの最初の項目が条件に一致する場合、このクエリは最初のクエリの約 5,000 倍の時間がかかります。
  • テーブル内の 1 つの項目が一致する場合、このクエリは最初のクエリより平均 2,500 倍長くかかります。
  • Titleクエリがおよび キー列のインデックスを利用できる場合、このクエリは最初のクエリの約半分の時間で済みます。

要約すると、あなたが次の場合:

  1. Entity Framework 4を使用する(新しいバージョンではクエリ構造が改善される可能性があるため) Entity Framework 6.1 以前 ( 6.1.1 にはクエリを改善するための修正があるため)、および
  2. テーブルに対して直接クエリを実行する (サブクエリを実行するのではなく)、および
  3. (述語の一部ではなく) 結果を直接使用する、AND
  4. また:
    1. クエリを実行しているテーブルに適切なインデックスが設定されている、または
    2. ほとんどの場合、アイテムが見つからないことが予想されます

.Any()THENの 2 倍の時間がかかると予想できます.Count()。たとえば、クエリに 50 ミリ秒ではなく 100 ミリ秒かかる場合や、5 ミリ秒ではなく 10 ミリ秒かかる場合があります。

他の状況では 、少なくとも同じくらい速く、場合によっては桁違いに速い.Any()はずです。.Count()

とにかく、これが実際に製品のパフォーマンス低下の原因であると判断するまでは、何が理解しやすいかをもっと気にする必要があります。.Any()あなたが本当に理解しようとしていることをより明確かつ簡潔に述べているので、それに固執してください。

于 2012-09-15T18:20:37.770 に答える
28

Any は、データベース レベルで「存在する」に変換されます。First は Select Top 1 に変換されます ... これらの間では、実際のオブジェクトを取得する必要はなく、ブール値の結果値のみを取得する必要があるため、Exists は First よりも優れたパフォーマンスを発揮します。

少なくとも、レコードが 1 つあると判断する前に、一致セット全体を評価して反復する必要がある .Where(x => x.Count() > 0) については質問しませんでした。リクエストをショートサーキットし、大幅に高速化できます。

于 2012-09-14T19:51:30.820 に答える
2

Any()クエリに変換されるため、より良い結果が得られると思われEXISTSます...しかし、EFはひどく壊れており、これを生成します(編集済み):

SELECT 
CASE WHEN ( EXISTS (SELECT 
    1 AS [C1]
    FROM [MyTable] AS [Extent1]
    WHERE Condition
)) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT 
    1 AS [C1]
    FROM [MyTable] AS [Extent2]
    WHERE Condition
)) THEN cast(0 as bit) END AS [C1]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]

それ以外の:

SELECT 
CASE WHEN ( EXISTS (SELECT 
    1 AS [C1]
    FROM [MyTable] AS [Extent1]
    WHERE Condition
)) THEN cast(1 as bit)
   ELSE cast(0 as bit) END AS [C1]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]

...基本的にクエリのコストが 2 倍になります (単純なクエリの場合、複雑なクエリの場合はさらに悪化します)

私は、使用する方がほとんど常に高速であることがわかりました(コストは、適切に作成されたクエリ.Count(condition) > 0とまったく同じです)EXISTS

于 2012-09-15T00:26:39.163 に答える
-1

Any()First()使用するとIEnumerable、物事を遅延評価するための柔軟性が得られます。ただしExists()、リストが必要です。

これで問題が解決し、どちらを使用するかを決めるのに役立つことを願っています.

于 2012-09-14T17:27:30.850 に答える