(質問はSOから移動しました)
クラスタ化インデックス付きのテーブル(ダミーデータ)に2つの列が含まれています。
次に、これら2つのクエリを実行します。
declare
@productid int =1 ,
@priceid int = 1
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid OR @productid IS NULL)
AND (priceid = @priceid OR @priceid IS NULL)
SELECT productid,
t.priceID
FROM Transactions AS t
WHERE (productID = @productid)
AND (priceid = @priceid)
両方のクエリの実際の実行プランは次のとおりです。
ご覧のとおり、1つ目はSCANを使用していますが、2つ目はSEEKを使用しています。
ただしOPTION (RECOMPILE)
、最初のクエリに追加して、SEEKを使用するように実行プランも作成しました。
DBAチャットの友達は私に次のように言いました:
クエリでは、@ productid = 1です。つまり、(productID = @ productID OR @productID IS NULL)は(productID = @ productID)に簡略化できます。前者は@productIDの任意の値を処理するためにスキャンを必要とし、後者はシークを使用できます。したがって、RECOMPILEを使用すると、SQL Serverは@productIDに実際にある値を調べ、その最適な計画を作成します。@productIDにnull以外の値を指定すると、シークが最適になります。@productIDの値が不明な場合、計画は@productIDの可能な値に適合している必要があり、スキャンが必要になります。警告:OPTION(RECOMPILE)は、実行するたびにプランを強制的に再コンパイルします。これにより、すべての実行に数ミリ秒が追加されます。これは、クエリが非常に頻繁に実行される場合にのみ問題になります。
また:
@productIDがnullの場合、どの値を求めますか?回答:求めることは何もありません。すべての値が対象です。
OPTION (RECOMPILE)
SQL Serverがパラメータの実際の値を確認し、それをシークできるかどうかを確認することを理解しています。
しかし、今、私は先行コンパイルの利点を失っています。
質問
IMHO-SCANは、paramがnullの場合にのみ発生します。
それは問題ありません-SQL SERVERにSCANの実行プランを作成させます。
しかし、SQL Serverがこのクエリを値を使用して何度も実行していることを検出した場合1,1
、なぜ別の実行プランを作成してSEEKを使用しないのですか?
AFAIK-SQLは、最もヒットしたクエリの実行プランを作成します。
SQL SERVERが以下の実行プランを保存しないのはなぜですか。
@productid int =1 , @priceid int = 1
(私はそれらの値で何度も実行します)
- SQLにその実行プラン(SEEKを使用)を保持するように強制することは可能ですか?