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

やあ、最近PostgreSQLのパフォーマンスチューニングで頭を抱えてるって?わかるよ。特にJSONBや配列型を使い始めると、普通のB-treeインデックスだけじゃ太刀打ちできなくなる瞬間があるよね。

今日はそんな君のために、PostgreSQLの「切り札」ことGIN(Generalized Inverted Index:汎用転置インデックス)について、実務でハマりやすいポイントを交えてガッツリ解説するよ。

—

GINインデックスって結局なんなの?

一言で言えば、「辞書の索引」だ。
例えば、本の後ろについてる索引を想像してほしい。「りんご」という単語が何ページにあるかを知りたいとき、全ページをめくらなくても、索引を見れば「15, 32, 88ページ」ってすぐわかるよね。

B-treeが「値そのもの」を木構造で管理するのに対し、GINは「値の中に含まれる要素」を分解して、それが「どのレコードにあるか」を管理する。だから、JSONBのキーや配列の要素、あるいは全文検索の単語単位での高速な検索が可能になるわけだ。

なぜGINは「更新」に弱いのか

実務でGINを使うとき、一番最初にぶつかる壁がこれだ。「読み取りは爆速なのに、INSERTやUPDATEが異様に重い」という問題。

なぜかというと、GINは「1つのデータ」を複数の「要素(キー)」に分解してインデックスに書き込むからなんだ。
例えば、`{“tags”: [“tech”, “postgres”, “db”]}` というJSONBを保存するとき、GINは「tech」「postgres」「db」という3つのキーに対して、それぞれインデックスの更新をかける。1回のINSERTで、内部的にはマルチタスクが走っているようなものだ。

救世主 `fastupdate` との付き合い方

この「更新の遅さ」を緩和するために用意されているのが `fastupdate` というパラメータだ。

CREATE INDEX idx_my_jsonb_data ON my_table USING GIN (data) WITH (fastupdate = on);

これが `on`(デフォルト)だと、インデックス更新の一部を「保留(Pending List)」に回して、後からまとめて反映させるようになる。これで書き込み性能は劇的に改善する。

ただし、ここからが現場の知恵だ。

この Pending List が肥大化すると、今度は「検索性能」が落ちる。検索のたびに、メインのインデックスとPending Listの両方を探しに行く必要があるからだ。

  • 書き込みが多いアプリなら: `fastupdate = on` は必須。
  • 読み取りがメインなら: `fastupdate = off` にして、インデックスを常に最新に保つ方が賢い。
  • 運用のアドバイス: 定期的に `gin_clean_pending_list()` を実行して、溜まったPending Listを掃除する運用を組むのが、ベテランのやり方だ。

実務で使いこなすためのTips

1. 範囲を絞るなら `jsonb_path_ops` を使え

デフォルトの `jsonb_ops` は、JSONBのあらゆる要素をインデックス化するからサイズが肥大化しやすい。特定のパス(例えば `data->’user’->’id’`)しか検索しないなら、演算子クラスに `jsonb_path_ops` を指定しよう。インデックスサイズが小さくなり、検索も高速になる。

— これだけでインデックスサイズが激減することがある
CREATE INDEX idx_jsonb_path ON my_table USING GIN (data jsonb_path_ops);

2. 検索条件に合わせる

GINは「包含演算子(@>)」を使うときが一番輝く。
`WHERE data @> ‘{“status”: “active”}’`
これ以外の条件(例えば、特定のキーが存在するかどうかだけを確認するような場合)だと、インデックスが効かないケースがある。実行計画(`EXPLAIN ANALYZE`)を見る癖は絶対につけておこうな。

最後に:完璧なインデックスなんてない

GINは強力だけど、銀の弾丸じゃない。
インデックスを貼れば貼るほど、書き込みコストは比例して増えていく。データベースの設計は「どこを捨てて、どこを最適化するか」というトレードオフの連続だ。

もし「GINを入れても重い…」と悩んだら、まずは `pg_stat_user_indexes` でインデックスのヒット率を見てみてくれ。そして、もしインデックスを貼るほどでもないカラムなら、思い切って外す勇気も必要だ。

何か具体的に困っているクエリがあるなら、またいつでも持ってきてよ。一緒に実行計画を眺めながら、ボトルネックを潰していこう。現場からは以上だ!

コメント

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