RDBMSのボトルネックは99%ディスクI/Oにある。CPUや物理メモリに比べて、ハードディスクの速度はかなり遅い。気が遠くなるぐらい遅い。インデックスを効果的に設計すれば劇的にディスクI/Oコストを減らすことができる。
インデックスって何だ?まず簡単に基礎知識。インデックスには、クラスタ化インデックスと非クラスタ化インデックスがある。大雑把に言えば、クラスタ化インデックスとはレコードデータ自体のディスク上での順序を表す。だから、テーブル毎に一つしか作れない。クラスタ化インデックスの順序が隣接しているという事は、データが物理的に隣接されてディスクに格納されているという事である。SQL Serverは、データを「ページ」という概念で格納する。I/Oは全てこの8KBのページが最小単位である。レコードをたった一行取得する場合でもページ毎に読み出される。クラスタ化インデックスの順序が近いデータは一つのページに含まれている可能性が高く、ページ読み込み数が少なくなり効率が良い。インデックス経由で検索する場合は、B-Tree(バランスドツリー)を辿る。クラスタ化インデックスの場合、リーフノードに到達すればデータ本体がある。隣り合うリーフノードはリンクリストで繋がれている。非クラスタ化インデックスの場合はリーフノードにデータはなく、データを識別する行ロケータがある(ヒープの場合は行ロケータ値、クラスタ化テーブルの場合はクラスタリングキー)。行ロケータからクラスタ化インデックスのキーとユニークキーを取得し、更にクラスタ化インデックスを辿りデータに到達する。(※1)。図からもわかる通り、範囲検索をする場合、クラスタ化インデックスは圧倒的に速い。一度レコードに到達すれば、あとは下方にあるレコードをスキャンしていくだけである。ページが異なっても隣のページにリンクされており、I/Oコストは最小限に抑えられる。一方、非クラスタ化インデックスは範囲検索にめっぽう弱い。非クラスタ化インデックス内のキーは一度にスキャンされるとはいえ、データ本体を探すためにクラスタ化インデックスのBツリーを何度も辿る。この時のI/Oコストは非常に大きい。テーブルスキャンの方が遥かににマシな場合もある。非クラスタ化インデックスは、特定の数件のレコードを探す事に適しているのだ。以上が基本知識。続けてインデックスの設計基準を。主キーにクラスタ化インデックスを作成するな主キーとなる列にクラスタ化インデックスを作成してはいけない。90%以上(むしろ100%と言たいぐらいだ)のシナリオでこのルールは成立すると断言する。テーブルの主キーとは、レコードを一意に特定するものだ。サロゲートキー(特に意味を持たない連番)であることも多々ある。後の仕様変更のリスクを避けるために、好んでサロゲートキーを使う設計者も多いだろう。そして大事なことであるが、主キーは範囲検索に滅多に(あるいは全く)使われない(※2)。SQL...
2011/02/26
登録:
投稿 (Atom)