【実務・中級編】 GINインデックス – PostgreSQL

「また遅いクエリ踏んじゃった……。これ、`jsonb`の中身を検索してるんだけど、インデックス効いてないっぽいんだよね」

先日、チームの後輩からこんな相談を受けました。PostgreSQLを使っていると避けては通れない、JSONBや配列型の検索問題ですね。テーブルが数万行ならまだしも、数百万行を超えたあたりで突然牙を剥いてくるこの悩み。

そんな時、僕がまず提示するのが「GINインデックス」という選択肢です。

今日は、教科書的な説明はさらっと流して、実務でどう使いこなすべきか、現場の温度感で解説していこうと思います。

—

GINって結局なんなの?

GINは「Generalized Inverted Index(汎用転置インデックス)」の略です。

ざっくりイメージするなら、「本の巻末にある索引」を想像してください。普通の本の索引って、単語が載っていて、その横にページ番号がズラッと並んでますよね?

「ある単語」をキーにして、「その単語が含まれるページ(行)」を即座に引き当てる。これがGINの正体です。B-Treeインデックスが「値の大小関係」を管理して範囲検索が得意なのに対し、GINは「一つのカラムの中に複数の値が含まれている状態(配列やJSONB)」を分解して、個別の値からレコードを逆引きするのに特化しています。

実践:JSONBに対する検索を爆速にする

例えば、ユーザーの属性情報をJSONBで持っているようなテーブルがあるとしましょう。

— こんな感じのテーブル
CREATE TABLE users (
id serial PRIMARY KEY,
attributes jsonb
);

この`attributes`の中に `{“tags”: [“admin”, “premium”, “beta”]}` のようなデータが入っていて、「premiumユーザーを検索したい!」というケース。

普通にクエリを書くとフルスキャン(Seq Scan)が走りますが、ここでGINを貼ると世界が変わります。

— GINインデックスを作成
CREATE INDEX idx_users_attributes ON users USING GIN (attributes);

これだけで、`@>` 演算子(包含演算子)を使った検索がめちゃくちゃ速くなります。

— これが爆速になる
SELECT FROM users WHERE attributes @> ‘{“tags”: [“premium”]}’;

ここで注意!「GINの弱点」も知っておこう

「じゃあ全部GINでいいじゃん!」と思うかもしれませんが、ここからが現場の知恵です。GINには明確な弱点があります。

1. 更新が重い:B-Treeは1行更新するだけですが、GINは「そのカラムに含まれる要素」すべてをインデックスに書き戻す必要があるため、INSERTやUPDATEがかなり重くなります。頻繁に書き換わるカラムには向きません。
2. インデックスサイズが大きい:データ構造上、どうしても肥大化しがちです。ストレージコストと相談が必要ですね。
3. 「全文検索」以外での制約:実はJSONBのキー全体に対してインデックスを貼るのか、特定のパスに対して貼るのかで戦略が変わります。

現場でよくやる「インデックスの最適化」

もし、「JSONB全体じゃなくて、特定のパスだけ検索したいんだよね」という場合は、`jsonb_path_ops` というオプションを使うのがプロの常套手段です。

— これだとデフォルトよりインデックスサイズが小さくなり、検索も速くなることが多い
CREATE INDEX idx_users_attributes_path ON users USING GIN (attributes jsonb_path_ops);

ただし、これを使うと `@>` 演算子以外の検索(キーの存在確認など)ができなくなる制限がある。このトレードオフを「要件」に合わせて判断するのが、エンジニアの腕の見せ所です。

最後に:使い所の見極めがすべて

GINは魔法の杖ではありません。

  • 読み取りメインのデータか?
  • JSONBや配列の中身をピンポイントで絞り込みたいか?
  • 書き込み負荷は許容範囲内か?

この3点を考えて、まずは検証環境で `EXPLAIN ANALYZE` を叩いてみてください。`Seq Scan` が `Bitmap Index Scan` に変わった瞬間のあの快感、ぜひ味わってほしいですね。

もし「GINを入れてみたけど、更新が遅すぎて使い物にならない!」なんてことがあったら、次は `btree_gin` 拡張や、そもそもJSONBの構成を見直す必要があるかもしれません。その時はまた相談してください。

データベース設計に銀の弾丸はありません。でも、引き出しを増やしておけば、大抵のパフォーマンス問題は解決できます。明日からのコーディング、インデックスのこと少しだけ意識してみてください。応援しています!

コメント

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