🐔

DBのIndex(IPAのDBスペシャリスト対策)

に公開

1.クラスタ化インデックスと非クラスタ化インデックス

1.1.クラスタ化インデックス(clustered index)

テーブルの実データそのものをインデックス順に並べ替える仕組み。当然、1つのテーブルに1つしか設定できない。

1.2.非クラスタ化インデックス(non-clustered index)

実データとは別に「検索用の辞書(索引)」を作成する仕組み。
テーブル本体の並び順はバラバラだが、インデックスには順序が与えられている。

1.3.B+木インデックスの例

例えば、「学科コード、学籍番号(主キー)、数学のテストの点数」の3列からなるテーブルを考える。

1.3.1. 学籍番号に「クラスタ化インデックス」を作る

CREATE TABLE student_score (
  dept_code   CHAR(2),
  student_id  INT PRIMARY KEY,   -- クラスタ化インデックスになる(多くのDBで)
  math_score  INT
);

このとき、多くのRDBMSでは PRIMARY KEY に クラスタ化インデックス が張られ、
テーブル本体は student_id 順に物理的に並んでいる。

1.3.2. 数学点数に「非クラスタ化インデックス」を作る

CREATE INDEX idx_math_score ON student_score(math_score);

このとき、DB内部には「別のB+木」ができて、キーは math_score で昇順に管理される。
各キーの葉ノードには「対応する行のポインタ(RowID または PK)」が格納される。

例(概念イメージ):

インデックス: math_score
  40 → student_id = 1023
  55 → student_id = 1005
  70 → student_id = 1002
  70 → student_id = 1008
  90 → student_id = 1011

1.3.3. クエリでの挙動

「点数が70点の学生を探す」

SELECT * FROM student_score WHERE math_score = 70;
  • インデックスで 70 をB+木から一発で見つける

  • ポインタをたどって student_id=1002,1008 の行を取得
    → 全件検索せず、必要行だけアクセスできる。

「学籍番号順で全件出せ」

SELECT * FROM student_score ORDER BY student_id;
  • 主キーがクラスタ化インデックスなので、テーブル本体をそのまま読み出すだけ。

  • 点数インデックスはまったく使われない。

「点数順でソートして出せ」

SELECT * FROM student_score ORDER BY math_score;
  • 非クラスタ化インデックスがすでに点数順で並んでいるので、これをなぞれば良い。

  • ただし、実データを取りに行くのにページへのランダムI/Oが発生する。
    → 大量件数だとコストが高い。

  • 「SELECT math_score FROM ...」のようにインデックス列だけを参照する場合、テーブル本体を参照せずインデックスだけで完結する。一方「SELECT *」の場合は必ずランダムI/Oが発生する。

1.4.クラスタ化インデックスと非クラスタ化インデックスの機能的違い

  • 検索機能自体は同じ
  • 実データを取りに行くときに、クラスタ化インデックスの場合は特定のページに固まっているが、非クラスタ化インデックスの場合は散らばっているのでページへのランダムI/Oが発生する。

※では巨大なページを作ればいいかというと、ページロックの場合の粒度や、キャッシュ効率の悪化などの問題が発生するので、そういうわけにもいかない。

2.主索引と副次索引

主索引とは、「主となる索引」というような曖昧なものではなく、「主キーに付与する索引」という意味であり、副次索引とは主キー以外の項目に対して付与する索引である。主キーが複数の列からなる場合、その一部の列に対して付与する索引も副次索引となる。

  • 主索引は、クラスタ化インデックスの場合が多い。
  • 1つのテーブルに、主索引と副次索引の両方を作ることもある。

Discussion