インデックスの基礎 — なぜ検索が速くなるのか
データベースのインデックスの仕組みを、本の索引にたとえて解説します。なぜ検索が速くなるのか、どの列に貼るべきか、効かないケースや貼りすぎの弊害まで、概念から整理します。
テーブルのデータが増えると、検索が遅くなっていきます。これを解決するのがインデックス(索引)です。インデックスはデータベースのパフォーマンスを支える重要な仕組みで、「なぜ速くなるのか」を理解すると、設計やチューニングの勘所がつかめます。この記事は概念の理解に重点を置きます。
本の索引と同じ仕組み
分厚い本から「ある単語」を探すことを考えます。最初のページから順に読んでいけば必ず見つかりますが、時間がかかります。一方、巻末の索引を引けば「その単語は 245 ページ」とすぐ分かります。
データベースのインデックスも同じです。インデックスがないと、データベースは全行を上から順に調べます(フルスキャン)。インデックスがあれば、索引をたどって目的の行に直接ジャンプできます。データ量が多いほど、この差は劇的になります。
仕組み: B-tree
多くのデータベースのインデックスは B-tree(ビーツリー)という木構造で作られています。値が大小の順に枝分かれして並んでいて、探したい値へ数回のステップでたどり着けます。
イメージとしては、辞書を引くのに似ています。「さ行 → し → しん…」と絞り込んでいくように、木をたどって候補を一気に狭めます。全ページをめくるのに比べて、比較の回数が圧倒的に少なくて済みます。
どの列に貼るべきか
インデックスは、検索や結合の条件によく使われる列に貼ると効果的です。
WHEREの条件になる列:WHERE email = ...のemailなどJOINの結合キー:ON orders.customer_id = customers.idの外部キー側ORDER BYで並べ替える列:並べ替えを索引の順序で肩代わりできる
逆に、めったに検索しない列や、値の種類が極端に少ない列(例: 性別のように 2 種類しかない)には、貼っても効果が薄いことがあります。
効かないケース
インデックスがあっても使われないことがあります。代表的なのは、列に加工をした条件です。
-- 列を加工すると、その列のインデックスが使われないことがある
WHERE LOWER(email) = 'a@example.com'
WHERE age + 1 = 30email にインデックスがあっても、LOWER(email) は「加工後の値」なので、元の列の索引と一致せずフルスキャンになりがちです。条件はできるだけ列をそのまま使う形に書くと、インデックスが効きやすくなります。
また、テーブルの大部分がヒットするような条件では、索引をたどるより全部読んだほうが速い、とデータベースが判断してインデックスを使わないこともあります。
貼りすぎの弊害
「速くなるなら全部の列に貼ればいい」とはなりません。インデックスにはコストがあります。
- 書き込みが遅くなる:行を追加・更新・削除するたびに、インデックスも更新する必要がある
- ディスクを消費する:インデックスは実データとは別に保存される
つまりインデックスは「検索は速く、書き込みは遅く」というトレードオフです。読み取りが多い列に絞って貼る、というバランス感覚が大切です。
まとめ
- インデックスは本の索引と同じで、全行を調べずに目的の行へ直接たどり着ける
- 多くは B-tree 構造で、値を大小順にたどって候補を絞る
WHERE/JOIN/ORDER BYでよく使う列が候補- 列を加工した条件では効かないことがある
- 貼りすぎると書き込みが遅くなり容量も食う(トレードオフ)
インデックスは「なぜ遅いのか」「どうすれば速くなるのか」を考える出発点です。仕組みを知っておくと、データベースと向き合うときの視野が広がります。