web-dev-qa-db-ja.com

SQLステートメントをsargableにするのはなぜですか?

定義により(少なくとも私が見たものから)sargableは、クエリが使用する実行計画をクエリエンジンで最適化できることを意味します。私は答えを調べてみましたが、主題についてはあまりないようです。質問は、SQLクエリをsargableにするものとしないものは何ですか?どんなドキュメントでも大歓迎です。

参考: SARGable

234
DForck42

クエリを引数なしにする最も一般的なことは、where句のfunction内にフィールドを含めることです。

SELECT ... FROM ...
WHERE Year(myDate) = 2008

SQLオプティマイザーは、myDateにインデックスが存在しても、それを使用できません。文字通り、テーブルのすべての行に対してこの関数を評価する必要があります。使用する方がはるかに良い:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

他の例:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 
237
BradC

これをしないでください:

WHERE Field LIKE '%blah%'

LIKE値はワイルドカード文字で始まるため、テーブル/インデックススキャンが発生します。

これをしないでください:

WHERE FUNCTION(Field) = 'BLAH'

これにより、テーブル/インデックススキャンが発生します。

データベースサーバーは、テーブル内のすべての行に対してFUNCTION()を評価し、それを「BLAH」と比較する必要があります。

可能であれば、逆に実行してください:

WHERE Field = INVERSE_FUNCTION('BLAH')

これにより、パラメータに対してINVERSE_FUNCTION()が1回実行され、引き続きインデックスの使用が許可されます。

75
beach

この回答では、データベースに十分なカバリ​​ングインデックスがあると想定しています。 このトピック については十分な質問があります。

多くの場合、クエリの可算性は、関連するインデックスの転換点によって決まります。転換点は、あるテーブルまたは結果セットを別のテーブルまたは結果セットに結合する際のインデックスのシークとスキャンの違いを定義します。もちろん、1回のシークはテーブル全体をスキャンするよりもはるかに高速ですが、多くの行をシークする必要がある場合は、スキャンの方が意味があります。

そのため、オプティマイザが1つのテーブルの結果の行数が次のテーブルの可能なインデックスの転換点よりも少ないと予想する場合、SQLステートメントはさらに引数を取りやすくなります。

詳細な投稿と例を見つけることができます here

操作を検索可能と見なすには、既存のインデックスを使用できるだけでは不十分です。上記の例では、where句のインデックス付きの列に対して関数呼び出しを追加すると、定義済みのインデックスを利用する可能性が最も高くなります。 「スキャン」、つまりその列(インデックス)からすべての値を取得し、指定されたフィルター値に一致しない値を削除します。行数が多いテーブルに対しては、まだ十分に効率的ではありません。 sargabilityを実際に定義しているのは、ソートされた項目の配列のハーフセット消去に依存するバイナリ検索方法を使用して、bツリーインデックスを走査するクエリ機能です。 SQLでは、「インデックスシーク」として実行プランに表示されます。

4
user2011845