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

「B-treeだけで満足してない?」PostgreSQLの奥義、GiSTインデックスを使いこなそう

こんにちは!最近、DBのパフォーマンスチューニングにどっぷり浸かっているエンジニアです。

PostgreSQLを触っていると、ほぼ間違いなく最初にお世話になるのがB-treeインデックスですよね。「とりあえずインデックスを貼るならB-tree」というのは、ある意味でエンジニアの生存戦略として正しいです。

でも、実務で複雑なデータを扱い始めると、B-treeの限界にぶつかる瞬間が必ずやってきます。「図形データ(GIS)を高速に検索したい」「範囲検索だけじゃなくて、もっと柔軟なクエリを投げたい」そんなとき、B-treeはそっと背を向けてしまうんです。

そこで登場するのが、今日の主役。GiST (Generalized Search Tree) です。これを知っていると、DB設計の引き出しがグッと広がりますよ。

—

GiSTって結局何モノなの?

一言で言うと、「どんなデータ構造にも対応できる、万能型のインデックスフレームワーク」です。

B-treeが「値の大小関係」をキーに整列させるのに対して、GiSTは「何らかの領域や特徴量」を抽象化してツリー構造に落とし込むイメージです。

内部的には、データを「包含関係(ある図形が別の図形を含んでいるか)」や「重なり」といった基準で分割します。これによって、幾何データ(Point, Polygonなど)や全文検索、さらには配列の包含判定まで、B-treeでは太刀打ちできないクエリを高速化できるんです。

—

実践!PostgreSQLでGiSTを使いこなす

一番よくあるユースケースとして、位置情報(GIS)を例に挙げてみましょう。`postgis`拡張を使っているなら必須の知識ですね。

1. 幾何データの検索

例えば、店舗の座標情報を持つテーブルがあるとします。

— 拡張の有効化
CREATE EXTENSION IF NOT EXISTS postgis;

— テーブル作成
CREATE TABLE shops (
id SERIAL PRIMARY KEY,
name TEXT,
location GEOMETRY(Point, 4326)
);

— GiSTインデックスを作成!
CREATE INDEX idx_shops_location ON shops USING GIST (location);

このインデックスがある状態で、特定のエリア内にある店を探すクエリを投げると……。

— 「この矩形の中にあるお店を教えて」というクエリ
SELECT name FROM shops
WHERE location && ST_MakeEnvelope(139.7, 35.6, 139.8, 35.7, 4326);

ここで使われている `&&` 演算子が、GiSTインデックスの真骨頂です。B-treeだとこうはいきません。

—

注意点:魔法の杖じゃない

ここまで聞くと「じゃあ何でもかんでもGiSTでいいじゃん!」と思うかもしれませんが、現場で使う際はいくつか注意が必要です。

  • 更新コストが高い: GiSTはツリーの再構築がB-treeより複雑で重たいです。書き込みが頻繁に発生するテーブルに貼ると、インデックスの更新でCPU負荷が跳ね上がることがあります。
  • クエリプランナの癖: GiSTは、時々クエリプランナが「シーケンシャルスキャンの方が速いな」と判断してインデックスを使わないことがあります。`EXPLAIN ANALYZE` を叩いて、本当にインデックスが効いているか確認する癖をつけましょう。
  • B-treeとの棲み分け: 単純な数値や文字列の等価比較・範囲比較なら、迷わずB-treeを使ってください。GiSTの方が汎用的な分、シンプルで高速なケースではB-treeに軍配が上がります。

—

現場のエンジニアへのアドバイス

僕が後輩によく言うのは、「インデックスは、クエリの『形』に合わせて選ぶものだ」ということです。

もし、あなたが扱っているデータが……

  • 位置情報(GPSなど)
  • 範囲検索が主体の複雑なデータ
  • 全文検索のインデックス(tsvectorなど)
  • 配列の中に特定の値が含まれるか判定したい

……といった要件に当てはまるなら、ぜひ一度 GiST の存在を思い出してください。

PostgreSQLは、ただデータを貯めるだけの箱ではありません。こういった高度なインデックスを使いこなすと、DB側でデータを整理・選別する能力が格段に上がります。「重い処理をアプリケーション側でやっていないかな?」と疑問に思ったときこそ、インデックスの出番です。

次回のチューニング案件では、ぜひ `USING GIST` を試してみてくださいね。それでは、良いDBライフを!

コメント

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