「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ライフを!
コメント