「LIKE検索が遅い…」と悩む君へ。PostgreSQLの「pg_trgm」で全文検索の沼から抜け出そう
現場で開発していると、一度はぶつかる壁があるよね。「ユーザーが検索窓に何を入れるか分からないから、とりあえず `LIKE ‘%keyword%’` で実装しておこう」というやつ。
最初はいいんだ。データが数千件くらいのうちはね。でも、数百万件を超えたあたりで突然クエリが重くなって、ユーザーから「検索が遅い!」というクレームが飛んでくる。DBを覗くと、`Seq Scan`(全件走査)が真っ赤に燃え上がっている……なんて経験、一度はあるはず。
そこで今回は、PostgreSQLの隠し球、`pg_trgm`(トリグラム)拡張について話そうと思う。これを知っているだけで、検索のパフォーマンスチューニングの引き出しがグッと広がるよ。
—
トリグラムって、結局なんなの?
トリグラム(trigram)とは、文字列を3文字ずつの塊に切り分けたものだよ。
例えば「apple」という言葉なら、「 a」「 ap」「app」「ppl」「ple」「le 」(スペースを境界として扱う)という具合だね。
この「3文字の断片」をインデックス化してDBに持たせるのが `pg_trgm` の役割なんだ。これがあれば、`LIKE ‘%keyword%’` のような「前方一致じゃない検索」でも、DBがインデックスを使って「どの行にその断片が含まれているか」を高速に特定できるようになる。
さっそく導入してみよう
まずは拡張機能を有効にする。これはスーパーユーザー権限が必要だから、本番環境ならDB管理者に頼むか、Dockerコンテナなら初期化スクリプトに入れておこう。
CREATE EXTENSION IF NOT EXISTS pg_trgm;
次に、検索したいカラムに対してインデックスを貼る。ここで大事なのは、通常の `B-tree` ではなく `GIST` または `GIN` インデックス を使うことだ。
— GINの方が検索は速いことが多いけど、インデックスの作成には時間がかかる
CREATE INDEX idx_trgm_user_name ON users USING gin (name gin_trgm_ops);
これで準備完了。この状態で `LIKE ‘%tanaka%’` みたいなクエリを投げれば、PostgreSQLは賢くインデックスを走査して、爆速で結果を返してくれるようになる。
—
実務で「これ、地味に便利だな」と思うシーン3選
ただ検索を速くするだけじゃない。現場でこの機能が「助かった!」となる瞬間をいくつか紹介するよ。
1. ユーザーの「うろ覚え検索」に対応する(類似度検索)
`pg_trgm` の真骨頂は、`%` 演算子を使った類似度検索だ。「スマホ」と検索したときに、「スマートホン」というデータもヒットさせたい。そんな時はこれだ。
— 類似度しきい値を設定(0.0〜1.0)
SET pg_trgm.similarity_threshold = 0.3;
— 似ているカラムを探す
SELECT name, similarity(name, ‘スマホ’) as score
FROM users
WHERE name % ‘スマホ’
ORDER BY score DESC;
これ、実装するとユーザーから「この検索、なんか気が利くな」ってすごく喜ばれる機能なんだよね。
2. 郵便番号やコードの「部分一致」
例えば、郵便番号や商品コードの一部を入力して検索させたいとき。`B-tree` だと前方一致しか効かないけど、`pg_trgm` なら中間一致も余裕だ。
3. 正規表現検索の高速化
`~` 演算子を使った正規表現検索も、`pg_trgm` インデックスがあれば劇的に速くなる。複雑なパターンマッチングをSQLだけで完結させたいときに重宝するよ。
—
最後に、先輩からの注意点
ここまで聞くと「最強じゃん!」と思うかもしれないけど、一つだけ心に留めておいてほしい。
「インデックスはタダじゃない」 ってこと。
`pg_trgm` のインデックスは、通常のインデックスよりもサイズが大きくなりがちだ。特に `GIN` インデックスは、更新(INSERT/UPDATE)のたびにインデックスの再構築が走るから、書き込みが多いテーブルに貼るとDB全体のパフォーマンスが落ちる可能性がある。
- 検索がメインのテーブル(ユーザー検索など)には最高。
- ログや決済データのような書き込み爆速テーブルには慎重に。
このバランス感覚を身につけると、一気に「できるエンジニア」っぽさが出てくるはずだよ。
もし「インデックスを貼ったのに遅いままなんだけど?」というときは、`EXPLAIN ANALYZE` を叩いて、本当にインデックスが使われているか確認する癖をつけよう。エンジニアの仕事は、推測することではなく、計測することだからね。
それじゃ、また現場で困ったことがあったら聞きに来てよ。応援してるよ!
コメント