複合インデックス

2列で絞るクエリ

実務でよく流れるのは、1列だけでなく複数の条件で絞るクエリです。

SELECT * FROM orders WHERE store_id = 3 AND ordered_on = DATE '2026-03-01';

このとき、store_id の索引と ordered_on の索引を別々に作るより、2列をまとめた1本の索引のほうがよく効きます。これを複合インデックスと呼びます。

CREATE INDEX orders_store_ordered_idx ON orders (store_id, ordered_on);

列の順番が意味を持つ

複合インデックスで最も重要なのが、列を書いた順番です。

電話帳を思い浮かべると分かります。姓、名の順に並んだ電話帳では、次のことができます。

探し方できるか
姓と名の両方が分かっているできる
姓だけ分かっているできる。その姓の範囲に絞れる
名だけ分かっているできない。全部めくることになる

索引もまったく同じです。(store_id, ordered_on) の索引は、store_id だけの条件でも使えますが、ordered_on だけの条件では絞り込めません

この性質を左端優先と呼びます。左から順に条件がそろっているぶんだけ使える、という意味です。

順番の決め方

どちらを左に置くかは、次の順で考えます。

1. 等号で絞る列を左に。 = 3 のように1点に決まる条件は、範囲条件より先に置きます。範囲条件を左に置くと、そこから右の列は絞り込みに使えなくなります。

2. 単独でも使う列を左に。 左端の列は単独の索引としても働くので、store_id だけで絞るクエリがあるなら store_id を左にします。

索引を1本減らせる

左端優先には嬉しい副作用があります。(store_id, ordered_on) があれば、store_id 単独の索引は要りません。複合インデックスが単独の索引を兼ねるからです。

索引は少ないほど書き込みが軽くなるので、兼ねられるものは兼ねさせます。設計表を作るときは、この重なりを必ず見ます。

手を動かす

複合インデックスを作り、条件の組み合わせを変えて計画がどう変わるかを見ます。

テーブル構造

CREATE TABLE orders ( id integer PRIMARY KEY, store_id integer NOT NULL, customer_id integer NOT NULL, ordered_on date NOT NULL, status text NOT NULL, total integer NOT NULL ); INSERT INTO orders SELECT g, 1 + (g % 5), 1 + (g % 20000), DATE '2026-01-01' + (g % 366), (ARRAY['paid', 'shipped', 'cancelled'])[1 + (g % 3)], 1000 + (g % 50000) FROM generate_series(1, 100000) AS g; ANALYZE orders;

期待される出力

has_indexmatched
155

ヒント

query.sql
学習モード
コードの実行結果
データベースを初期化中...