PostgreSQL 複合インデックス徹底解説!初心者でもわかるデータベース高速化のコツ
生徒
「データベースからデータを探すのが遅くて困っています。インデックスを貼ればいいと聞いたのですが、項目が2つ以上あるときはどうすればいいんですか?」
先生
「それは『複合インデックス』の出番ですね。名字と名前が分かれている名簿から、特定の人を素早く見つけるような仕組みのことですよ。」
生徒
「複数の項目をセットにするってことですか?順番とかも関係あるんでしょうか。」
先生
「その通りです!実は順番がとても重要なんです。料理のレシピ本で『食材』から探すか『料理名』から探すかのような違いがあります。パソコンを触ったことがなくてもわかるように、図解を交えて説明しますね。」
1. インデックスと複合インデックスの基本
データベースにおける「インデックス」とは、本でいうところの「索引(さくいん)」や、図書館の「図書目録」のようなものです。PostgreSQL(ポストグレスキューエル)というデータベース管理ソフトでは、このインデックスを上手に使うことで、膨大なデータの中から一瞬で目的の情報を見つけ出すことができます。
通常、1つの項目(例えば「名前」だけ)に貼るものを単一インデックスと呼びますが、今回のテーマである「複合インデックス」は、複数の項目(例えば「名字」と「名前」)をセットにして作成する索引のことです。
例えば、100万人分のデータが入った会員名簿を想像してください。そこから「東京都に住んでいる、30歳の、佐藤さん」を探したいとき、1ページ目から順番に見ていくと日が暮れてしまいますよね。複合インデックスは、あらかじめ「住所・年齢・名前」をセットにして整理しておくことで、辞書をめくるようにパッとその場所に辿り着ける魔法のリストなのです。
2. なぜ「順番」がそんなに大事なのか?
複合インデックスを理解する上で最も重要なルールは、「設定する項目の順番」です。これは、電話帳や辞書が「あいうえお順」で並んでいるのと同じ理屈です。
例えば、「名字」と「名前」の順番でインデックスを作ったとします。この場合、データはまず名字で並べ替えられ、同じ名字の中でさらに名前順に並びます。
この仕組みには以下のような特徴があります。
- 「名字」だけで検索する場合: 索引が使えるので速い。
- 「名字」と「名前」の両方で検索する場合: 索引が最大限に活かされるので非常に速い。
- 「名前」だけで検索する場合: 索引が使えません。名字がバラバラな状態で名前だけを探そうとしても、索引の並び順と一致しないからです。
このように、複合インデックスは「左側(先頭)」に指定した項目から順番に効果を発揮します。これを「最左接頭辞(さいさぜっとうじ)の原則」と呼びます。難しい言葉ですが、「左側の項目を飛ばして検索はできない」と覚えておけば大丈夫です。
3. 実際にテーブルを作って試してみよう
まずは、お店の顧客データを管理するテーブル(表)を用意してみましょう。ここでは「都道府県(pref)」と「年齢(age)」の2つの項目を使って検索することを考えます。
id | name | pref | age | score
---+----------+----------+-----+-------
1 | 田中一郎 | 東京都 | 25 | 80
2 | 山田花子 | 大阪府 | 25 | 90
3 | 佐藤健太 | 東京都 | 30 | 75
4 | 鈴木美咲 | 神奈川県 | 22 | 85
5 | 伊藤直樹 | 東京都 | 25 | 95
6 | 高橋愛子 | 大阪府 | 40 | 70
このデータに対して、「東京都に住む25歳の人」を探すための複合インデックスを作成する命令(SQL)は以下のようになります。
CREATE INDEX idx_pref_age ON customers (pref, age);
この命令を実行すると、データベースの中に「都道府県」と「年齢」が綺麗に並んだ専用の裏リストが作成されます。この裏リストがあるおかげで、検索速度が飛躍的に向上します。
SELECT *
FROM customers
WHERE pref = '東京都' AND age = 25;
id | name | pref | age | score
---+----------+----------+-----+-------
1 | 田中一郎 | 東京都 | 25 | 80
5 | 伊藤直樹 | 東京都 | 25 | 95
4. インデックス設計の落とし穴:絞り込み率(カーディナリティ)
次に、どの項目を先に持ってくるべきかを考えます。ここで「カーディナリティ」という用語が登場します。これは簡単に言うと「データの種類の多さ」のことです。
例えば、「性別(男女)」は種類が少ないのでカーディナリティが低いと言います。逆に「電話番号」や「メールアドレス」は一人ひとり違うのでカーディナリティが高いと言います。効率の良いインデックスを作るには、一般的に「データをより大きく絞り込める項目(種類が多い項目)」を左側に持ってくるのが定石です。
しかし、PostgreSQLの複合インデックスにおいては、それ以上に「どのような検索条件(WHERE句)が頻繁に使われるか」が重要です。いくら種類が多くても、検索で使われない項目を先頭にしても意味がないからです。
5. 範囲検索(不等号)を使う場合の注意点
「20歳以上」や「1月1日以降」といった、範囲を指定してデータを探す場合、複合インデックスの設計にはさらに注意が必要です。実は、範囲指定を行う項目は、インデックスの中で「一番最後」にするのが最も効率的です。
例えば、「店舗ID」が一致し、かつ「売上日」が一定期間内のデータを探す場合を考えてみましょう。
id | shop_id | sales_date | amount
---+---------+------------+-------
1 | 101 | 2025-01-01 | 5000
2 | 102 | 2025-01-01 | 3000
3 | 101 | 2025-01-02 | 8000
4 | 103 | 2025-01-02 | 4500
5 | 101 | 2025-01-03 | 2000
この場合、インデックスは (shop_id, sales_date) の順番で作るのが正解です。先に shop_id で場所を特定し、その範囲内で日付をスキャンする方が、データベースにとっては作業が楽だからです。
CREATE INDEX idx_shop_date ON sales (shop_id, sales_date);
SELECT *
FROM sales
WHERE shop_id = 101 AND sales_date >= '2025-01-02';
id | shop_id | sales_date | amount
---+---------+------------+-------
3 | 101 | 2025-01-02 | 8000
5 | 101 | 2025-01-03 | 2000
6. インデックスを貼りすぎることのデメリット
「検索が速くなるなら、全部の組み合わせにインデックスを貼ればいいじゃないか!」と思うかもしれません。しかし、それには大きな落とし穴があります。
インデックスは、データが追加(INSERT)されたり書き換え(UPDATE)されたりするたびに、裏側で作り直されています。つまり、インデックスが多すぎると、データの保存や更新の動きが非常に重くなってしまうのです。また、インデックス自体もディスク容量を消費します。スマートな設計とは、最小限のインデックスで最大限の検索パターンをカバーすることなのです。
7. 並べ替え(ORDER BY)を高速化する複合インデックス
複合インデックスのもう一つの強力なメリットは、データの「並べ替え」も速くしてくれることです。例えば、ブログ記事のリストを表示するときに「カテゴリーごとに、新しい順で表示する」という処理はよくありますね。
-- カテゴリーIDで絞り込み、投稿日時が新しい順に並べる
SELECT title, category_id, posted_at
FROM posts
WHERE category_id = 5
ORDER BY posted_at DESC;
このような場合、(category_id, posted_at) という順番で複合インデックスを作っておくと、データベースはわざわざ並べ替え作業をすることなく、インデックスから順番にデータを取り出すだけで済みます。人間が並べ替える必要のない、あらかじめ整理された棚から商品を取り出すようなイメージです。これにより、大量の投稿があってもサクサク表示されるようになります。
8. パフォーマンスを確認する魔法の言葉「EXPLAIN」
実際にインデックスが使われているかどうかを確認する方法があります。それが EXPLAIN(エクスプレイン)という命令です。日本語で「説明する」という意味ですね。
使い方は簡単で、実行したいSQLの前に EXPLAIN をつけるだけです。すると、データベースが「どのインデックスを使って、どうやってデータを探すつもりか」という計画を教えてくれます。
EXPLAIN SELECT * FROM customers WHERE pref = '東京都';
結果の中に Index Scan という文字があれば、無事にインデックスが使われています。もし Seq Scan(シーケンシャルスキャン)と出ていたら、それは「全部のデータを最初から最後まで探している」という状態なので、インデックスの設計を見直す必要があるかもしれません。プロのエンジニアも、この画面を見ながら「ああでもない、こうでもない」と最適なインデックスを探るのです。
9. 初心者がまず覚えるべき複合インデックスの3箇条
最後に、ここまでの内容を整理して、設計の時に意識すべきポイントを3つにまとめます。
- 左側から使う: 検索条件で必ず指定する項目、またはイコール(=)で絞り込む項目をインデックスの左側に配置する。
- 範囲検索は右側へ:
>や<などの範囲指定をする項目は、複合インデックスの構成要素の中で一番右側に置く。 - 欲張りすぎない: 本当に必要な検索パターンに絞って作成する。何でもかんでもインデックスを作ると、データの保存が遅くなる。
データベースのチューニングは、パズルのような面白さがあります。最初は難しく感じるかもしれませんが、「どうすればコンピュータが楽にデータを見つけられるか」という思いやりの心で設計してみると、自然と良いインデックスが作れるようになりますよ。