PostgreSQLのINCLUDE句付きインデックスと複合インデックスの違いを徹底解説

PostgreSQL

PostgreSQLでは、検索性能を向上させるためにインデックスを作成しますが、近年よく利用される機能としてINCLUDE句を使ったインデックスがあります。

INCLUDE句付きインデックスは、一見すると複数列を指定する複合インデックスと似ています。しかし、内部的な役割や検索条件で利用される仕組みには大きな違いがあります。この記事では、INCLUDE句と通常の複合インデックスの違い、使い分けるポイント、具体的な利用例について解説します。

PostgreSQLのINCLUDE句とは

PostgreSQLのINCLUDE句は、インデックスに検索条件として使用しない列を追加保存するための機能です。

例えば、以下のようなテーブルがあるとします。

CREATE TABLE orders(
order_id INTEGER,
customer_id INTEGER,
order_date DATE,
amount INTEGER
);

customer_idで検索しながらamountも取得したい場合、以下のようなインデックスを作成できます。

CREATE INDEX idx_orders_customer
ON orders(customer_id) INCLUDE(amount);

この場合、customer_idが検索条件として利用され、amountはインデックス内に保持されるだけになります。

通常の複合インデックスとは何が違うのか

通常の複合インデックスでは、複数の列すべてがインデックス検索の対象になります。

例えば以下のようなインデックスを作成した場合です。

CREATE INDEX idx_orders_customer_amount
ON orders(customer_id, amount);

この場合、customer_idとamountの両方がインデックスキーとして扱われます。そのため、検索条件や並び替え条件によっては両方の列が検索性能に影響します。

一方、INCLUDE句で指定した列はインデックスキーではありません。あくまでインデックス内部に保存される追加データという位置付けです。

項目 複合インデックス INCLUDE句付きインデックス
指定列の役割 検索キーになる 検索キーにはならず保持のみ
WHERE条件で利用 利用可能 基本的に利用不可
ORDER BYで利用 利用可能 利用不可
主な目的 検索条件の高速化 インデックスオンリースキャンの促進

INCLUDE句を使うメリット

INCLUDE句の大きなメリットは、インデックスオンリースキャンを利用しやすくなる点です。

通常、SQLで検索すると、まずインデックスから対象行を探し、その後テーブル本体(ヒープ)へアクセスして必要な列を取得します。

しかし、検索に必要な列と取得したい列がすべてインデックス内に存在すれば、テーブル本体へアクセスせずに結果を返せる場合があります。これがインデックスオンリースキャンです。

例えば以下のSQLを考えます。

SELECT customer_id, amount
FROM orders
WHERE customer_id = 100;

customer_idだけをインデックスキーにし、amountをINCLUDEで保持しておけば、検索条件を満たしながら取得列もインデックス内で完結できます。

複合インデックスを使うべきケース

複合インデックスは、複数の列を検索条件や並び替え条件として利用する場合に適しています。

例えば以下のような検索を頻繁に行う場合です。

SELECT * FROM orders
WHERE customer_id = 100
AND order_date > '2025-01-01';

この場合、customer_idとorder_dateの両方が検索条件になるため、以下のような複合インデックスが有効です。

CREATE INDEX idx_orders_search
ON orders(customer_id, order_date);

このインデックスでは、2つの列が検索キーとして利用されるため、条件検索の高速化につながります。

INCLUDE句を使うべきケース

INCLUDE句は、検索条件として利用する列と、SELECT結果として取得したいだけの列を分けたい場合に向いています。

例えば、商品一覧画面で商品IDによる検索を行い、商品名や価格も表示するケースを考えます。

CREATE INDEX idx_product_id
ON products(product_id)
INCLUDE(product_name, price);

product_idは検索に使用し、product_nameやpriceは表示用データとして保存されます。

このような場合、すべてを複合インデックスにすると不要な検索キーが増え、インデックスサイズが大きくなる可能性があります。

INCLUDE句を使う際の注意点

INCLUDE句で追加した列もインデックス容量を消費します。そのため、むやみに多くの列を追加すると、インデックスサイズが肥大化し、更新処理の負荷が増える可能性があります。

また、INCLUDE列は検索条件には利用されないため、以下のようなSQLでは期待した効果が得られません。

SELECT * FROM orders
WHERE amount = 1000;

amountをINCLUDEしていても、amountによる検索速度向上には直接つながりません。この場合はamountをキー列に含めたインデックスが必要になります。

PostgreSQLでのインデックス設計の考え方

インデックス設計では、どの列が検索条件になるのか、どの列が取得結果として必要なのかを分けて考えることが重要です。

WHERE句やORDER BYで頻繁に利用する列は通常のインデックスキーに設定し、検索には不要だがSELECTで取得する列はINCLUDE句で追加すると、効率的な設計になります。

例えば、ユーザー検索画面で「メールアドレスで検索して名前を表示する」という処理なら、メールアドレスをキー列、名前をINCLUDE列にする設計が考えられます。

まとめ

PostgreSQLのINCLUDE句付きインデックスと通常の複合インデックスは、どちらも複数列を扱えますが目的が異なります。

複合インデックスは指定した列を検索キーとして利用するため、WHERE句やORDER BYの高速化に向いています。

一方、INCLUDE句付きインデックスは検索キーではない列をインデックス内に保持し、インデックスオンリースキャンによる取得性能向上を目的として利用します。

検索条件に使う列はインデックスキー、表示用に取得するだけの列はINCLUDE句というように役割を分けることで、PostgreSQLのインデックス性能を最大限に引き出せます。

コメント

タイトルとURLをコピーしました