PostgreSQLで複数の列を対象にした複合インデックスを作成する場合、列をどの順番で指定するかによって検索性能が大きく変わることがあります。同じ列を使ったインデックスでも、順序が違うだけで効率的に利用されないケースもあります。
この記事では、PostgreSQLの複合インデックスで列順を決める基本的な考え方や、WHERE句・ORDER BY句との関係、実際の設計例を紹介します。データベースのパフォーマンス改善を行う際の判断基準として活用してください。
PostgreSQLの複合インデックスとは
複合インデックスとは、複数の列を組み合わせて作成するインデックスのことです。
例えば、ユーザー情報を管理するusersテーブルで、以下のようなインデックスを作成するとします。
CREATE INDEX idx_users_country_age ON users(country, age);
この場合、country列とage列を組み合わせたインデックスが作成されます。しかし、PostgreSQLでは列を指定した順番が重要になります。
idx_users_country_ageとidx_users_age_countryは同じ列を利用していますが、内部的な並び方が異なるため、利用できる検索条件も変わります。
複合インデックスの列順は左端の列を重視する
PostgreSQLの複合インデックスは、基本的に左側の列から順番に検索条件へ利用されます。
例えば、以下のインデックスがあるとします。
CREATE INDEX idx_orders_customer_date ON orders(customer_id, created_at);
この場合、customer_idを指定した検索ではインデックスが有効に利用されやすくなります。
SELECT * FROM orders WHERE customer_id = 100;
一方で、created_atだけを条件にした検索では、このインデックスの効果は限定的になります。
SELECT * FROM orders WHERE created_at > '2026-01-01';
そのため、複合インデックスを設計するときは「どの列を最初に検索条件として利用することが多いか」を考えることが重要です。
選択性が高い列を先にする考え方
複合インデックスの列順を決める基準として、選択性(カーディナリティ)があります。
選択性とは、検索した際に対象データをどれだけ絞り込めるかを表す指標です。値の種類が多く、検索結果が少なくなる列ほど選択性が高いと言えます。
例えば、以下のようなusersテーブルがあるとします。
| 列名 | 特徴 |
|---|---|
| 性別 | 男性・女性など数種類しかない |
| メールアドレス | ユーザーごとに異なる |
この場合、メールアドレスの方が選択性が高いため、検索条件として頻繁に利用するなら先頭列に向いています。
ただし、選択性だけで決めるのではなく、実際のSQLの利用パターンも合わせて判断する必要があります。
WHERE句の条件の使われ方から列順を決める
実際のアプリケーションでは、どのようなWHERE条件で検索されるかを確認して列順を決定します。
例えば、注文履歴を検索する処理で以下のSQLが頻繁に実行される場合を考えます。
SELECT * FROM orders WHERE user_id = 10 AND status = '発送済';
この場合、以下のようなインデックスが候補になります。
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
user_idで利用者を絞り込み、その後statusで状態を確認する流れになるため、この検索パターンでは効率的です。
逆にstatusだけで検索する処理が多い場合は、statusを先頭にする設計が適している可能性があります。
ORDER BYや範囲検索がある場合の注意点
複合インデックスの列順は、並び替えや範囲検索にも影響します。
例えば、以下のような検索を考えます。
SELECT * FROM logs WHERE user_id = 100 ORDER BY created_at DESC;
この場合、以下のインデックスが有効になる可能性があります。
CREATE INDEX idx_logs_user_created ON logs(user_id, created_at DESC);
user_idで対象を絞り込み、その中でcreated_at順に並んだ状態になるため、ORDER BYの処理負荷を減らせます。
一方で、先頭列で範囲検索を行う場合、その後ろの列が効きにくくなることがあります。
例えば、日付範囲で大量のデータを絞り込む場合、その後に指定した列の検索効果が低下するケースがあります。
よくある複合インデックス設計の考え方
複合インデックスの列順を決める際には、以下のような優先順位で考えると設計しやすくなります。
- 検索条件で必ず指定される列
- データを大きく絞り込める列
- ORDER BYで利用される列
- JOIN条件で利用される列
例えば、ECサイトの商品検索で「カテゴリ」「販売状態」「登録日時」で検索する場合、実際に利用される検索条件を確認して順序を決めます。
カテゴリ指定が必須で、その後に販売状態で絞り込み、登録日時順に表示するなら、以下のような設計が考えられます。
CREATE INDEX idx_products_category_status_date ON products(category_id, status, created_at);
作成後はEXPLAINで効果を確認する
複合インデックスは、作成しただけで必ず高速化するとは限りません。実際にSQLがインデックスを利用しているか確認することが重要です。
PostgreSQLではEXPLAIN ANALYZEを使って実行計画を確認できます。
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 100;
結果にIndex ScanやBitmap Index Scanなどが表示されていれば、インデックスが利用されている可能性があります。
もしSeq Scan(全件走査)になっている場合は、データ量や条件、インデックス設計を見直す必要があります。
まとめ
PostgreSQLで複合インデックスの列順を決める場合、単純に選択性が高い列を先頭にするだけではなく、実際の検索パターンを基準に考えることが重要です。
基本的には、WHERE句で頻繁に指定される列を左側に配置し、その後に絞り込み条件や並び替えに使う列を配置します。
また、インデックス作成後はEXPLAIN ANALYZEで実際の実行計画を確認し、アプリケーションの利用状況に合わせて調整することで、PostgreSQLの性能を最大限に引き出せます。


コメント