sql >> データベース >  >> RDS >> Sqlserver

Entity Framework クエリのパフォーマンスは、未加工の SQL 実行と極端に異なります

    この回答では、元の観察に焦点を当てています。EF によって生成されたクエリは遅いですが、同じクエリを SSMS で実行すると高速です。

    この動作の考えられる説明の 1 つは、パラメータ スニッフィング .

    そのため、EF はパラメーターがほとんどないクエリを生成します。このクエリを初めて実行すると、サーバーは最初の実行で有効だったパラメータの値を使用して、このクエリの実行プランを作成します。その計画は通常かなり良いです。ただし、後でパラメーターに他の値を使用して同じ EF クエリを実行します。パラメーターの新しい値に対して、以前に生成されたプランが最適ではなく、クエリが遅くなる可能性があります。サーバーは以前のプランを使用し続けます。これは、パラメーターの値が異なるだけで、同じクエリであるためです。

    この時点で、クエリ テキストを取得して SSMS で直接実行しようとすると、技術的には EF アプリケーションによって発行されるクエリと同じではないため、サーバーは新しい実行プランを作成します。 1 文字の違いでも十分です。サーバーがクエリを新しいクエリとして処理するには、セッション設定の変更でも十分です。その結果、サーバーはキャッシュ内に一見同じクエリに対して 2 つのプランを持っています。最初の「遅い」計画は、最初は異なるパラメーター値用に作成されたものであるため、パラメーターの新しい値に対しては低速です。 2 番目の「高速」プランは、現在のパラメーター値に対して構築されるため、高速です。

    記事 アプリケーションでは遅く、SSMS では速い Erland Sommarskog 著では、この分野およびその他の関連分野についてより詳細に説明しています。

    キャッシュされたプランを破棄し、サーバーにプランを強制的に再生成させる方法はいくつかあります。テーブルを変更するか、テーブルのインデックスを変更することで、このテーブルに関連するすべてのプラン (「低速」と「高速」の両方) を破棄する必要があります。次に、パラメーターの新しい値を使用して EF アプリケーションでクエリを実行し、新しい "高速" プランを取得します。 SSMS でクエリを実行し、パラメーターの新しい値を使用して 2 番目の "高速" プランを取得します。サーバーは引き続き 2 つの計画を生成しますが、現在は両方の計画が高速です。

    別の亜種は OPTION(RECOMPILE) を追加しています クエリに。このオプションを使用すると、サーバーは生成されたプランをキャッシュに保存しません。したがって、クエリが実行されるたびに、サーバーは実際のパラメーター値を使用して、指定されたパラメーター値に最適であると (サーバーが考える) 計画を生成します。マイナス面は、プラン生成の追加オーバーヘッドです。

    サーバーは、たとえば古い統計のために、このオプションで「悪い」計画を選択する可能性があることに注意してください。しかし、少なくとも、パラメータ スニッフィングは問題になりません。

    OPTION (RECOMPILE) の追加方法が気になる方 EF によって生成されるクエリへのヒントは、この回答をご覧ください:

    https://stackoverflow.com/a/26762756/4116017



    1. SQLの複数の文字を置き換える

    2. MySQL:レコード間の平均間隔

    3. mysql-選択クエリの行をロックしますか?

    4. sqlalchemy同じテーブルへの複数の外部キー