SQLステートメントを検索可能にするのは何ですか?


252

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

参考:SARGable


58
「検索可能」の場合は+1。それが今日の私の一日の言葉です。:-p
BFree

1
また、Adamの答えに加えて、情報の山はほとんどの場合、各DBエンジンに非常に特有であると付け加えます。
Hoagie

30
SARG = ARGumentを検索します。おもしろいのは、ドイツ語で「SARG」は「棺」を意味するので、人々がSARGABLEについて話すときはいつも笑顔で笑わなければなりません。棺に入れることができますか?:-)
marc_s 2009

検索可能性は環境によって異なります。MySQLのドキュメントはこちら:dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer

「ルックアップテーブル」の代わりにフリーテキストフィールドを使用することも、クエリを検索可能にするという趣旨に反します。ユーザーはフリーテキスト(町の名前など)を入力するときに、スペルを間違えますが、ルックアップテーブルでは、ユーザーは正しいスペルのエントリを選択する必要があります。述語でLIKE '%...%'を使用する代わりに、適切にインデックスを付けることができるので、少し余分なトラブルの価値があります。
リバースエンジニア、

回答:


256

クエリが引数を使用できないようにする最も一般的なことは、where句の関数内にフィールドを含めることです。

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()) 

7
内部に関数を含める GROUP BYと、クエリが検索不可能になりますか?
マイクベイリー

1
一部のデータベースエンジン(Oracle、PostgreSQL)は式のインデックスをサポートしていますが、ご存知ですか?
クレイグ、

3
のより良いバージョンは思いWHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL?最適化の担当者から、OR句をwhere句で使用するとクエリの検索を解除できると言われました。
High Plains Grifter、2015年

2
@HighPlainsGrifterそのクエリにはUNION ALLを使用する必要があります-ユニオンには暗黙の一意性があるため、相互に排他的なデータセットを必要とする場合に必要なクエリよりもクエリのコストが高くなります
Devin Lamothe

1
@BradCでMSSQL 2016は、間には、実行計画の違いはありませんSelect ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))。どちらもFullNameのインデックスを使用し、インデックスシークを実行します。
CEGRD 2018

79

これを行わないでください:

WHERE Field LIKE '%blah%'

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

これを行わないでください:

WHERE FUNCTION(Field) = 'BLAH'

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

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

可能であれば、それを逆に行います。

WHERE Field = INVERSE_FUNCTION('BLAH')

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


5
関数の反転に関する提案は、関数がデータを往復するときにのみ機能します(つまり、f(f(n))= nを意味します)。
アダムロビンソン

5
そうだね。INVERSE_FUNCTIONの追加を検討しましたが、混乱させたくありませんでした。変更します。
ビーチ

9

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

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

したがって、オプティマイザが1つのテーブルの結果の行の数が次のテーブルの可能なインデックスの転換点よりも少ないことを期待している場合、SQLステートメントは特にsargableです。

詳細な投稿と例については、こちらをご覧ください


4

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.