次のようなクエリがある場合:
Select EmployeeId
From Employee
Where EmployeeTypeId IN (1,2,3)
フィールドにインデックスがありEmployeeTypeId
ますが、SQLサーバーは引き続きそのインデックスを使用しますか?
はい、そのとおり。Employee
テーブルに10,000レコードがあり、(1,2,3)に5レコードしかない場合EmployeeTypeId
、ほとんどの場合、インデックスを使用してレコードをフェッチします。ただし、9,000レコードにEmployeeTypeId
in(1,2,3)が含まれていることがわかった場合は、テーブルスキャンを実行して対応するを取得する可能性が高くなります。これは、テーブルEmployeeId
全体を実行する方が、それぞれに移動するよりも高速であるためです。インデックスツリーのブランチを作成し、レコードを個別に確認します。
SQL Serverは、クエリの実行方法を最適化するために多くのことを行います。ただし、正しい答えが得られない場合もあります。SQL Serverがインデックスを使用していないことがわかっている場合は、クエリアナライザで実行プランを確認することで、クエリに次の変更を加えて特定のインデックスを使用するようにクエリエンジンに指示できます。
SELECT EmployeeId FROM Employee WITH (Index(Index_EmployeeTypeId )) WHERE EmployeeTypeId IN (1,2,3)
EmployeeTypeId
フィールドにあるインデックスの名前が。であると仮定しますIndex_EmployeeTypeId
。
通常、IN句がテーブルの多くをカバーしていない限り、テーブルスキャンを実行します。特定のケースを見つける最良の方法は、クエリアナライザで実行し、実行プランを確認することです。
したがって、「IN」句がテーブルスキャンを実行する可能性がありますが、オプティマイザはそれを処理するための最良の方法を試してみますか?
インデックスが使用されるかどうかは、テーブル内のデータのタイプと分布、テーブル統計の最新性、および列の実際のデータタイプほど、クエリのタイプによって大きく異なりません。 。
他のポスターは、次の場合にテーブルスキャンでインデックスが使用されることを示しています。
それほど明白ではないかもしれない他の変数は、比較されている値のデータ型が同じであることを確認することです。PostgreSQLでは、floatでフィルタリングしている場合、インデックスは使用されないと思いますが、列はintで構成されています。インデックスの使用をサポートしない演算子もいくつかあります(ここでも、PostgreSQLではILIKE演算子はこのようなものです)。
ただし、前述のように、疑わしい場合は常にクエリアナライザを確認してください。DBMSのドキュメントは友だちです。
テクノロジーが最近想像もつかないほど改善されていない限り、表示されている「IN」クエリは、「IN」リストの値ごとに 1 つずつ、3 つの結果セットを事実上 OR 演算した結果を生成します。IN 句は各リストの等価条件になり、必要に応じてインデックスを使用します。一意の ID と十分な大きさのテーブルの場合、オプティマイザーがインデックスを使用することを期待します。
ただし、リスト内の項目が一意でなく、この例で "TypeId" が外部キーであると推測する場合、分散にもっと関心があります。オプティマイザーがリスト内の各値の統計をチェックするかどうか疑問に思っていますか? 最初の値をチェックして、それが行の 20% にあることがわかったとします (重要なほど大きなテーブルの)。おそらくテーブルスキャンになります。しかし、他の 2 つが一意であっても、同じクエリ プランが使用されるでしょうか?
それはおそらく議論の余地があります-従業員テーブルのようなものは、メモリにキャッシュされたままになるほど十分に小さい可能性が高く、おそらくそれとインデックス付き検索の違いに気付かないでしょう。
そして最後に、私が説教している間は、IN 句のクエリに注意してください。多くの場合、何かを機能させるための迅速な方法であり、(少なくとも私にとっては) 要件を表現するための良い方法になる可能性がありますが、ほとんどの場合、次のように言い換える方が適切です結合。あなたのオプティマイザーはこれを見つけるのに十分賢いかもしれませんが、そうでないかもしれません. 現在、本番データ ボリュームに対してパフォーマンス チェックを行っていない場合は、そうしてください。最近のコスト ベースの最適化では、完全な負荷と代表的な統計が得られるまで、クエリ プランを確認することはできません。それができない場合は、本番環境でのサプライズに備えてください...
@Mike: 詳細な分析をありがとう。そこには間違いなくいくつかの興味深い点があります。私が投稿した例はやや些細なことですが、質問の基礎は NHibernate の使用に由来しています。
NHibernate を使用すると、次のような句を記述できます。
int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))
NHibernate は次のようなクエリを生成します。
select * from employee where employeeid in (1, 5, 23463, 32523)
あなたや他の人が指摘しているように、インデックスが使用されるか、テーブルスキャンが発生する場合があるように見えますが、実行時までそれを実際に判断することはできません.