次のクエリの実行が遅い場合があります。
SELECT C.CustomerID
FROM dbo.Customers C WITH (NOLOCK)
WHERE C.Forename = @Forename
AND C.Surname = @Surname
OPTION (RECOMPILE)
CustomerIDはCustomersテーブルの主キーです。 Customersテーブルには、次の2つの非クラスター化インデックスもあります。
CREATE NONCLUSTERED INDEX idx_Forename ON Customers (Forename ASC)
CREATE NONCLUSTERED INDEX idx_Surname ON Customers (Surname ASC)
入力した姓と名の両方でクエリを実行すると、クエリオプティマイザーは次の実行プランのようにインデックス 'idx_Surname'を使用します。
このクエリは、この特定の検索が完了するまでに2分以上かかり、結果は見つかりません。入力された値の場合、@ Surnameは31,162レコードに一致しますが、@ ForenameはCustomersテーブルに一致しません。 @surnameのみで検索すると、31,162レコードが次のプランで1秒未満で返されます。
ForenameとSurnameの両方を含む検索のクエリを最適化するために、次のカバリングインデックスを追加しました。
CREATE NONCLUSTERED INDEX idx_Surname_Covering ON dbo.Customers (Surname) INCLUDE (Forename)
次に、ForenameとSurnameの両方を含むクエリは1秒未満で返されます。ただし、実際の実行計画ではカバリングインデックスは使用されません。
そう、
pS上記のクエリは分離された例であり、姓または名、またはその両方を検索でき、Customersテーブルには、独自のインデックスを持つ他の検索可能な列も含まれます。この詳細は質問に関連するとは考えられなかったので、ここには含めません。
1)カバリングインデックスが必要か、またはパフォーマンスを改善するためのより良い方法があるか
最高のインデックス
最適なインデックスは、テーブルにアクセスするクエリの最もカバーする選択的なインデックスです。
テーブルを例にとると、firstname = Johnである行が50000行ありますが、lastname = 'McClane'である行は1つだけです。Johnを最初のキー値またはMcClaneとしてインデックスを作成する必要がありますか?
回答:
それは場合によって異なります... John Mcclaneを常に検索している場合は、姓のインデックスを最初に作成するオープンとシャットダウンのケースです。しかし、Constanthin Smithを検索するクエリもあるとしたらどうでしょう。スミスを5000個以上持つことができますが、コンスタンティンは5つだけです。
その結果、それはあなたのクエリとあなたが求めているもの、それらがどれだけ実行されるかによって異なります...
クエリが常に名と姓の両方を検索する場合は、最初のキー列としてより選択的なものを選択するのは簡単なケースです。読み取りパフォーマンスの向上は、書き込みパフォーマンスの低下よりも大きくなるはずであることに留意してください。
もちろん、(firstname、lastname)と(lastname、firstname)の2つのインデックスを作成するように制限されている人は誰もいません。
(あなたの更新/挿入/削除ステートメントは可能性があります)。
フィルターされたインデックスなどを考慮しない場合、例に最適なインデックスは次のようになります
CREATE NONCLUSTERED INDEX idx_Forename_Surname ON dbo.Customers (Forename,Surname)
2)追加のカバリングインデックスにより、実際の実行プランのインデックスがidx_Forenameからidx_Surnameに変更されるのはなぜですか?
これは単にインデックスのせいではなく、インデックス作成の結果として作成された統計のせいだと思います。
これらの統計はidx_Surnameの統計と同じですが、「fullscan」で作成されているため、サンプルレートが大きい(100)と考えられます。
インデックスidx_Surname
によって作成された統計情報で統計の自動更新が発生した場合、それらのサンプルレートが小さく、推定が不適切であった可能性があります(例:1%のサンプルレート)。
この理論をテストするには、idx_Surname_Covering
インデックスとその統計を削除し、dbo.Customers
の統計を100%のサンプルレート(フルスキャン)で更新してみてください。
UPDATE STATISTICS dbo.Customers WITH FULLSCAN
うまくいけば、より良いシークを使用するための計画が変更されます。
これがクエリが変更された理由であり、メンテナンスウィンドウでのフルスキャンによる統計の更新が実行可能なオプションではない場合、 サンプルレート を変更できます