「データベースが遅い…」そんな悩みを抱えていませんか?
データベースを扱っていると、データ量が増えるにつれて検索速度がどんどん遅くなってしまうことがあります。そんなときに活躍するのが「インデックス」という機能です。
この記事では、SQLのインデックスについて、仕組みから使い方まで分かりやすく解説していきます。難しい専門用語は最小限にして、実際の例を交えながら説明するので、データベース初心者の方でも安心して読み進められますよ。
SQLのインデックスとは?基本の仕組み

インデックスの基本概念
インデックスとは、データベースの検索速度を向上させるための仕組みです。
分かりやすく例えるなら、本の索引(さくいん) のようなものだと考えてください。本の最後にある索引を使えば、目的の言葉が何ページに書いてあるかすぐに見つけられますよね。
データベースのインデックスも、これと全く同じ役割を果たします。
なぜインデックスが必要なのか
データベースにインデックスがない状態では、データを探すときに全てのレコード(データの行)を1つずつチェックする必要があります。
これを「フルスキャン」や「テーブルスキャン」と呼びます。
例えば、10万件のデータから特定の1件を探す場合を考えてみましょう。
インデックスなしの場合:
- 1件目から順番に確認していく
- 最悪の場合、10万件すべてをチェックする必要がある
- 時間がかかりすぎてしまう
インデックスありの場合:
- 索引を使って目的のデータの場所を素早く特定できる
- 数回の検索で目的のデータにたどり着ける
- 劇的に速度が向上する
インデックスの種類と特徴
データベースには、いくつかの種類のインデックスが用意されています。それぞれの特徴を見ていきましょう。
主キー(プライマリーキー)インデックス
主キーに自動的に作成されるインデックスです。
主キーとは、テーブル内の各レコードを一意に識別するための列のこと。例えば、ユーザーテーブルの「ユーザーID」などがこれに該当します。
特徴:
- 重複する値を持てない
- NULL値を含めない
- テーブルごとに1つだけ設定できる
- 自動的にインデックスが作成される
ユニークインデックス
重複を許さない値に対して設定するインデックスです。
主キーとの違いは、1つのテーブルに複数設定できる点。メールアドレスやユーザー名など、重複してはいけないデータに使われます。
特徴:
- 重複する値を持てない
- NULL値を含められる(データベースによって異なる)
- 複数の列に設定可能
通常のインデックス
最も一般的なインデックスです。
検索条件として頻繁に使用される列に設定することで、検索パフォーマンスを大幅に改善できます。
特徴:
- 重複する値を持てる
- NULL値を含められる
- 最も柔軟に使える
複合インデックス
複数の列を組み合わせて作成するインデックスです。
例えば、「都道府県」と「市区町村」の2つの列を組み合わせて検索することが多い場合、この2つをまとめて複合インデックスにすると効果的です。
特徴:
- 複数の列をまとめて管理する
- 列の順序が重要になる
- 検索条件の組み合わせによって効果が変わる
インデックスの仕組みを理解しよう
B-Treeインデックスの構造
多くのデータベースで採用されているのが「B-Tree(ビーツリー)」という構造です。
B-Treeは木構造のデータ構造で、以下のような特徴があります:
- データが階層的に整理されている
- バランスが保たれているため、検索効率が良い
- 挿入や削除を行ってもパフォーマンスが安定している
検索の流れ:
- ルートノード(木の根)から検索を開始
- 目的の値がある方向に枝を辿る
- 数回の比較で目的のデータに到達
この仕組みにより、大量のデータでも高速な検索が実現できます。
インデックスのメリット
インデックスを適切に使うことで、以下のようなメリットが得られます。
検索速度の向上:
WHERE句やJOIN句で指定する列にインデックスを設定すると、データの抽出が高速化されます。
ソート処理の効率化:
ORDER BY句で並び替える列にインデックスがあれば、ソート処理も速くなります。
ユニーク制約の実現:
ユニークインデックスを使えば、データの重複を防ぐことができます。
インデックスのデメリット
便利なインデックスですが、注意すべき点もあります。
ストレージ容量の増加:
インデックスは別途データとして保存されるため、ディスク容量を消費します。
書き込み処理の低下:
データを挿入・更新・削除するときに、インデックスも同時に更新する必要があるため、これらの処理が遅くなります。
不適切なインデックスは逆効果:
むやみにインデックスを作りすぎると、かえってパフォーマンスが低下することがあります。
インデックスの作成方法
基本的な作成構文
インデックスを作成するには、CREATE INDEX文を使用します。
CREATE INDEX インデックス名 ON テーブル名 (列名);
実例:
-- usersテーブルのemail列にインデックスを作成
CREATE INDEX idx_email ON users (email);
ユニークインデックスの作成
重複を許さないインデックスを作る場合は、UNIQUEキーワードを追加します。
CREATE UNIQUE INDEX インデックス名 ON テーブル名 (列名);
実例:
-- usersテーブルのusername列にユニークインデックスを作成
CREATE UNIQUE INDEX idx_username ON users (username);
複合インデックスの作成
複数の列をまとめてインデックス化する場合は、カンマで区切って列名を指定します。
CREATE INDEX インデックス名 ON テーブル名 (列名1, 列名2);
実例:
-- ordersテーブルのuser_idとorder_dateの複合インデックス
CREATE INDEX idx_user_order ON orders (user_id, order_date);
注意点:
複合インデックスでは、列の順序が重要です。上記の例では、user_idを指定した検索には効果的ですが、order_dateだけを指定した検索では効果が薄くなります。
インデックスを効果的に使うコツ
インデックスを設定すべき列
以下のような列には、インデックスを設定すると効果的です。
WHERE句で頻繁に使われる列:
検索条件として頻繁に使用される列にインデックスを設定しましょう。
-- emailで検索することが多い場合
SELECT * FROM users WHERE email = 'example@example.com';
JOIN句で使われる列:
テーブルを結合する際に使用する列にもインデックスが有効です。
-- user_idでJOINする場合
SELECT * FROM orders
JOIN users ON orders.user_id = users.id;
ORDER BY句で使われる列:
並び替えの基準となる列にインデックスがあると、ソート処理が高速化されます。
-- created_atで並び替えることが多い場合
SELECT * FROM posts ORDER BY created_at DESC;
インデックスを避けるべき列
逆に、以下のような列にはインデックスを設定しても効果が薄いか、逆効果になることがあります。
カーディナリティが低い列:
カーディナリティとは、列に含まれる値の種類の多さのことです。性別(男/女)のように選択肢が少ない列では、インデックスの効果が薄くなります。
頻繁に更新される列:
データの更新が多い列にインデックスを設定すると、更新のたびにインデックスも更新されるため、パフォーマンスが低下します。
小規模なテーブル:
数百件程度の小さなテーブルでは、インデックスを作ってもあまり効果が感じられません。
インデックスのメンテナンス
インデックスは作って終わりではありません。定期的なメンテナンスが重要です。
不要なインデックスの削除:
使われていないインデックスは、ストレージを無駄に消費し、書き込み処理を遅くします。定期的に見直して削除しましょう。
DROP INDEX インデックス名 ON テーブル名;
インデックスの再構築:
データの挿入や削除を繰り返すと、インデックスが断片化して効率が低下することがあります。データベースによっては、再構築機能が用意されています。
実践的な使用例
ケース1:ユーザー検索の最適化
会員制サイトで、メールアドレスによるログイン機能を実装する場合を考えてみましょう。
改善前:
-- インデックスなし
SELECT * FROM users WHERE email = 'user@example.com';
このクエリは、usersテーブルの全レコードをスキャンするため、ユーザー数が増えると非常に遅くなります。
改善後:
-- emailにユニークインデックスを作成
CREATE UNIQUE INDEX idx_email ON users (email);
-- 同じクエリでも高速化
SELECT * FROM users WHERE email = 'user@example.com';
メールアドレスは重複しないため、ユニークインデックスが最適です。
ケース2:注文履歴の検索最適化
ECサイトで、特定ユーザーの注文履歴を日付順に表示する機能を考えます。
改善前:
-- インデックスなし
SELECT * FROM orders
WHERE user_id = 123
ORDER BY order_date DESC;
改善後:
-- user_idとorder_dateの複合インデックス
CREATE INDEX idx_user_order ON orders (user_id, order_date);
-- 検索とソートが両方高速化
SELECT * FROM orders
WHERE user_id = 123
ORDER BY order_date DESC;
複合インデックスを使うことで、検索とソートの両方が効率化されます。
ケース3:カテゴリ別の商品検索
商品データベースで、カテゴリとステータスを組み合わせて検索する場合です。
改善前:
-- インデックスなし
SELECT * FROM products
WHERE category_id = 5
AND status = 'active';
改善後:
-- category_idとstatusの複合インデックス
CREATE INDEX idx_category_status ON products (category_id, status);
-- 複合条件の検索が高速化
SELECT * FROM products
WHERE category_id = 5
AND status = 'active';
よくある質問と回答
Q1. インデックスはいくつまで作れますか?
技術的な上限はデータベースシステムによって異なりますが、実用上は必要最小限に抑えるべきです。
目安としては、1つのテーブルに5〜10個程度が適切です。それ以上作ると、書き込み処理のパフォーマンスが著しく低下する可能性があります。
Q2. 既存のテーブルにインデックスを追加できますか?
はい、いつでも追加できます。
ただし、大量のデータが入っているテーブルにインデックスを作成する場合、作成処理に時間がかかることがあります。本番環境で実行する際は、アクセスが少ない時間帯を選ぶなどの配慮が必要です。
Q3. インデックスを作りすぎるとどうなりますか?
以下のような問題が発生します:
- データ挿入・更新・削除の速度が低下する
- ストレージ容量を大量に消費する
- データベースのメンテナンスコストが増加する
「必要な場所に必要なだけ」が基本原則です。
Q4. プライマリーキーとユニークインデックスの違いは?
主な違いは以下の通りです:
プライマリーキー:
- テーブルに1つだけ設定できる
- NULL値を許可しない
- テーブルの主要な識別子
ユニークインデックス:
- 複数設定できる
- NULL値を許可する(データベースによる)
- 補助的な一意性制約
まとめ
SQLのインデックスは、データベースの検索速度を劇的に向上させる強力な機能です。
この記事のポイントをおさらいしましょう。
インデックスの基本:
- 本の索引のように、データの場所を素早く見つける仕組み
- B-Tree構造により高速な検索が可能
- 主キー、ユニーク、通常、複合など種類がある
効果的な使い方:
- WHERE句、JOIN句、ORDER BY句で使う列に設定する
- カーディナリティが高い列を優先する
- 必要最小限の数に抑える
注意点:
- 書き込み処理が遅くなる
- ストレージ容量を消費する
- 定期的なメンテナンスが必要
適切にインデックスを設定すれば、ユーザーの待ち時間を減らし、快適なシステムを構築できます。
まずは検索条件として頻繁に使う列から、インデックスを試してみてはいかがでしょうか。実際のパフォーマンス改善を体感できるはずですよ。

コメント