この節では、MicrosoftのSQL Serverにおける 最も良く現われる実行計画の処理を説明します。Microsoftの ドキュメントも参照して下さい。
インデックスとテーブルへのアクセス
SQL Serverの用語はシンプルになっています。
「Scan」はインデックス全体を読み込み、「Seek」はインデックスあるいはテーブルの指定された一部のみにアクセスするためにBツリーや
物理アドレス(RID
、
Oracleで言うROWID
)を使う処理になっています。
- Index Seek, Clustered Index Seek
Index Seek
は、Bツリーの走査に 加えて、一致するエントリを探すのにリーフノードチェーンをたどります。第1章1, 「 SQLインデックスの内部構造」も参照して下さい。- Index Scan, Clustered Index Scan
インデックスの全体つまり全行を、インデックスの順番に沿って読みます。様々なシステム統計情報に基づき、 インデックスの順序に沿って全行が必要と判断した時、データベースはこの処理を実行します。例えば、対応する
order by
句がある時などです。- Key Lookup (Clustered)
クラスタ化インデックスから 1行を取り出します。これは、Oracleの索引構成表に対する
INDEX UNIQUE SCAN
と同じです。「データのクラスタリング: インデックスの強力さの2つ目」も参照して下さい。- RID Lookup (Heap)
テーブルから1行を取り出します。Oracleの
TABLE ACCESS BY INDEX ROWID
に当ります。「 SQLインデックスの内部構造」も参照して下さい。- Table Scan
フルテーブルスキャンとして知られる処理です。 テーブル全体つまり全行・全列をディスクに保存されている通りに読みます。複数ブロックの読み出し処理により、
Table Scan
の速度は大幅に改善されはしますが、最も重い処理の1つである事に 変わりありません。IO処理も多いですが、Table Scan
では 全てのテーブルの行の値をチェックしなければならないので、かなりのCPU時間も消費します。「フルテーブルスキャン」も参照して下さい。
協力してください
この記事が気に入ったら、私の書いた本「SQLパフォーマンス詳解」や私によるトレーニングもきっと気にいるはず。
結合処理
通常、結合処理で同時に処理できるのは2テーブルまでです。1つのクエリにそれ以上の結合対象のテーブルがある場合、 まず2つのテーブルを結合し、それからその中間結果を次のテーブルと結合するというように、順番に処理されます。結合の話をする場合には、 「テーブル」という言葉は「中間結果」の事を指す場合もあるのです。
- Nested Loops
片方のテーブルから結果を取り出し、その結果をもう1つの テーブルの各行に対して問い合わせて、2つのテーブルを結合します。SQL Serverでは、インデックスアクセスの後にテーブルデータを取り出すのにも入れ子のループ処理を使います。「入れ子ループ」も参照して下さい。
- Hash Match
ハッシュマッチ結合では、 結合の片方から候補となるレコードをハッシュテーブルにロードし、それを結合のもう片方の各行と突き合わせます。「ハッシュ結合」も参照して下さい。
- Merge Join
マージ結合は、 並べ替えられた2つのリストをジッパーのようにマージします。結合の両辺は事前にソートしておく必要があります。「ソートマージ」も参照して下さい。
ソートとグルーピング
- Sort
order by
句に従って、結果をソートします。この処理は、 中間結果(パイプライン化されていないもの)をマテリアライズするために、非常に多くのメモリを必要とします。「インデックスを使ったorder by」も参照して下さい。- Sort (Top N Sort)
order by
句に従って、結果セットの一部をソートします。パイプライン化された実行ができない場合は、 最初のN件のみを選択するクエリとして実行します。「最初のN行のみの選択」も参照して下さい。- Stream Aggregate
group by
句に従って、 並べ替え済みの結果セットをまとめます。この処理は中間結果をバッファせず、パイプライン化して実行します。「インデックスを使ったgroup by」も参照して下さい。- Hash Match (Aggregate)
レコードをグルーピングするのに一時的なハッシュテーブルを使います。 この処理では、データセットは事前にソートされている必要はありませんが、 中間結果(パイプライン化されていないもの)をマテリアライズするために非常に多くのメモリを必要とします。出力は、 一定のルールに沿って並べられているわけではないものになります。「インデックスを使ったgroup by」も参照して下さい。
最初のN件のみを選択するクエリ
- Top
必要な行数が取り出せた時点で、内部的な処理を中断します。「最初のN行のみの選択」も参照して下さい。
最初のN件のみを選択するクエリの効率は、 内部で動作する処理の実行モードに依存します。
Sort
のような、 パイプライン化されていない処理を途中で中断する動作の時は、非常に非効率になります。