SQL Server実行計画では、インデックススキャンとインデックスシークの違いは何ですか
私はSQL Server 2005を使用しています。
インデックススキャンは、SQLサーバーがインデックス全体を読み取って一致を探す場所です。これにかかる時間は、インデックスのサイズに比例します。
インデックスシークは、SQLサーバーがインデックスのbツリー構造を使用して、一致するレコードを直接シークする場所です(これがどのように機能するかについては http://mattfleming.com/node/192 を参照してください) -所要時間は、一致するレコードの数にのみ比例します。
従うべき基本的なルールは、スキャンが悪い、シークが良いということです。
インデックススキャン
SQL Serverはスキャンを実行するときに、ディスクからメモリに読み込むオブジェクトをロードし、そのオブジェクトを上から下に向かって読み取り、必要なレコードを探します。
インデックスシーク
SQL Serverがシークを実行すると、インデックス内のデータの場所がわかるため、ディスクからインデックスをロードし、必要なインデックスの部分に直接移動して、必要なデータの終わりまで読み取ります。 SQLは、検索対象のデータの場所を既に知っているため、これは明らかにスキャンよりもはるかに効率的な操作です。
スキャンの代わりにシークを使用するように実行プランを変更するにはどうすればよいですか?
SQL Serverがデータを探しているとき、おそらくSQL Serverがシークからスキャンに切り替える最大の理由の1つは、探している列の一部が使用するインデックスに含まれていないことです。ほとんどの場合、SQL Serverはクラスター化インデックススキャンの実行にフォールバックします。クラスター化インデックスにはテーブル内のすべての列が含まれているためです。これは、少なくとも私の意見では、インデックスのインデックス付きカラムにそれらのカラムを追加せずに、インデックス内のカラムをINCLUDEできるようになった最大の理由の1つです。インデックスに追加の列を含めることで、インデックスのサイズを大きくしますが、SQL Serverがインデックスを読み取ることを許可します。これらの値を取得するためにクラスター化インデックスまたはテーブル自体に戻る必要はありません。
参考文献
SQL Server実行計画内のこれらの各演算子の詳細については、「...」を参照してください.
インデックススキャン:
スキャンは、資格があるかどうかに関係なく、テーブル内のすべての行に触れるため、コストはテーブル内の行の総数に比例します。したがって、テーブルが小さい場合、またはほとんどの行が述部に適格である場合、スキャンは効率的な戦略です。
インデックスシーク:
シークは修飾する行とこれらの修飾行を含むページにのみ触れるため、コストはテーブル内の行の総数ではなく、修飾する行とページの数に比例します。
インデックススキャンは、最初のページから最後のページまでのデータページをスキャンすることに他なりません。テーブルにインデックスがあり、クエリが大量のデータに触れている場合、つまりクエリがデータの50%または90%以上を取得している場合、オプティマイザーはすべてのデータページをスキャンしてデータ行を取得します。インデックスがない場合、実行プランにテーブルスキャン(インデックススキャン)が表示される場合があります。
インデックスシークは、高度に選択的なクエリには一般的に推奨されます。つまり、クエリが要求する行数が少なくなるか、テーブルの行の残りの10行(一部のドキュメントでは15%と言われます)を取得するだけです。
一般に、クエリオプティマイザーは、インデックスシークを使用しようとします。つまり、オプティマイザーはレコードセットを取得するための有用なインデックスを見つけました。ただし、テーブルにインデックスがないか、有用なインデックスがないためにこれができない場合、SQL Serverはクエリ条件を満たすすべてのレコードをスキャンする必要があります。
スキャンとシークの違いは?
スキャンは、テーブルまたはインデックス全体を返します。シークは、述語に基づいてインデックスの1つ以上の範囲から行を効率的に返します。たとえば、次のクエリを検討してください。
select OrderDate from Orders where OrderKey = 2
スキャン
スキャンでは、ordersテーブルの各行を読み取り、述語「where OrderKey = 2」を評価し、述語がtrueの場合(つまり、行が条件を満たす場合)、行を返します。この場合、述部を「残余」述部と呼びます。パフォーマンスを最大化するために、可能な限りスキャンの残余述語を評価します。ただし、述語が高すぎる場合は、別のフィルター反復子で評価する場合があります。残余述語は、WHEREキーワードを使用したテキストのshowplan、またはタグを使用したXML showplanに表示されます。
以下は、スキャンを使用したこのクエリのテキストshowplan(簡潔にするために少し編集されています)です。
| –Table Scan(OBJECT:([ORDERS])、WHERE:([ORDERKEY] =(2)))
次の図は、スキャンを示しています。
スキャンは、資格があるかどうかに関係なく、テーブル内のすべての行に触れるため、コストはテーブル内の行の総数に比例します。したがって、テーブルが小さい場合、またはほとんどの行が述部に適格である場合、スキャンは効率的な戦略です。ただし、テーブルが大きく、ほとんどの行が条件を満たさない場合は、必要以上に多くのページと行にアクセスし、より多くのI/Oを実行します。
シーク
例に戻って、OrderKeyにインデックスがある場合、シークがより良い計画である可能性があります。シークでは、インデックスを使用して、述語を満たす行に直接移動します。この場合、述語を「シーク」述語と呼びます。ほとんどの場合、シーク述語を残留述語として再評価する必要はありません。インデックスは、シークが条件を満たす行のみを返すようにします。シーク述語は、SEEKキーワードを使用したテキストshowplanまたはタグを使用したXML showplanに表示されます。
シークを使用した同じクエリのテキストshowplanは次のとおりです。
| –Index Seek(OBJECT:([ORDERS]。[OKEY_IDX])、SEEK:([ORDERKEY] =(2))ORDERED FORWARD)
次の図は、シークを示しています。
シークは修飾する行とこれらの修飾行を含むページにのみ触れるため、コストはテーブル内の行の総数ではなく、修飾する行とページの数に比例します。したがって、高度に選択的なシーク述語がある場合、シークは通常、より効率的な戦略です。つまり、テーブルの大部分を削除するシーク述部がある場合です。
showplanに関するメモ
Showplanでは、スキャンとシーク、およびヒープ(インデックスのないオブジェクト)、クラスター化インデックス、非クラスター化インデックスのスキャンを区別します。次の表に、有効なすべての組み合わせを示します。
https://blogs.msdn.Microsoft.com/craigfr/tag/scans-and-seeks/
短い答え:
インデックススキャン:特定の列を除くすべての行をタッチします。
インデックスシーク:特定の行と特定の列をタッチします。
インデックススキャンでは、一致する行を見つけるためにインデックス内のすべての行がスキャンされます。これは、小さなテーブルに対して効率的です。インデックスシークでは、実際に基準を満たす行に触れるだけでよいため、一般的にパフォーマンスが向上します。
インデックススキャンは、インデックス定義が単一の行で検索述語を満たすことができない場合に発生します。この場合、SQL Serverは複数ページをスキャンして、検索述語を満たす行の範囲を見つける必要があります。
インデックスシークの場合、SQL Serverはindex定義を使用して、検索述語と一致する単一行を見つけます。
インデックスシークはより効果的です。
スキャンは、テーブルのすべての行にタッチします。
シークは、探している行のみを調べます。
シークは、データを検索する方法がより効率的であるため、スキャンよりも常に優れています。
良い説明を見つけることができます ここ