PostGISの空間インデックスとANALYZEを理解する:地理空間クエリの高速化実践ガイド

当ページのリンクには広告が含まれています。
🚀
データベース専門性を活かしてキャリアアップするなら

お疲れ様です!IT業界で働くアライグマです!

PostGISで地理空間データを扱うプロジェクトに参加していると、「なぜか位置情報検索が遅い」「インデックスを作ったはずなのに効いていない」という問題に遭遇することがあります。

筆者も以前、数百万件の店舗データを持つプロジェクトで、「半径5km以内の店舗検索」に10秒以上かかるという問題に悩まされました。結論から言えば、空間インデックスの設計ミスとANALYZE不足が原因でした。

本記事では、PostGISの空間インデックス(GiSTインデックス)の仕組みと、ANALYZE統計情報の役割を理解し、地理空間クエリを劇的に高速化する方法を解説します。

目次

PostGISの空間インデックスとは

💡 データベース・インフラのスキルを武器にキャリアアップしたい方へ
年収アップ・海外リモート・高単価案件など、専門性を活かした働き方を実現しませんか

空間インデックスは、地理空間データに対する検索を高速化するためのデータ構造です。PostgreSQLの通常のB-Treeインデックスは一次元データ向けですが、地理空間データは二次元(あるいは三次元)なので、専用のインデックスが必要になります。

GiSTインデックスの仕組み

PostGISでは主にGiST(Generalized Search Tree)インデックスを使用します。GiSTはR-Tree構造をベースにしており、空間オブジェクトを「バウンディングボックス(最小外接矩形)」で階層的に管理します。

  • バウンディングボックス:各ジオメトリを囲む最小の矩形
  • 階層構造:ルートから葉まで、空間を再帰的に分割
  • クエリ時の動作:検索範囲と重なるボックスだけを辿ることで、検索対象を絞り込む
-- 空間インデックスの作成
CREATE INDEX idx_shops_geom ON shops USING gist(geom);

-- インデックスのサイズ確認
SELECT pg_size_pretty(pg_relation_size('idx_shops_geom'));

データベースのパフォーマンスチューニングは実装の細部に宿ります。Rails8でSQLiteを本番運用する記事も参考にしてください。

IT女子 アラ美
B-Treeインデックスとは何が違うんですか?普通のインデックスじゃダメなんでしょうか。

ITアライグマ
B-Treeは一次元データ向けなので、「Aより大きくBより小さい」という比較しかできません。空間データは「この範囲に含まれるか」という二次元の比較が必要なので、GiSTが必要なんですね。

ANALYZEと統計情報の重要性

空間インデックスを作っても、クエリプランナーが正しく使ってくれないケースがあります。その原因の多くは、統計情報(カタログ情報)の不足です。

空間インデックス適用前後のクエリ性能比較

ANALYZEの役割

PostgreSQLのクエリプランナーは、テーブルの統計情報をもとに最適な実行計画を選択します。ANALYZEコマンドは、この統計情報を更新します。

  • 行数推定:テーブルにどれくらいのデータがあるか
  • 値の分布:どのような値がどれくらいの頻度で出現するか
  • 空間的な広がり:ジオメトリがどの程度の領域に分布しているか
-- テーブルの統計情報を更新
ANALYZE shops;

-- 特定カラムの統計情報を確認
SELECT attname, n_distinct, correlation
FROM pg_stats
WHERE tablename = 'shops' AND attname = 'geom';

統計情報が古いとどうなるか

統計情報が実際のデータと乖離していると、クエリプランナーは間違った推定をしてしまいます。データベースの内部動作を理解することが重要で、Goで実装するヘッドレスワークフローエンジンでも触れたトランザクション設計の考え方が参考になります。

  • シーケンシャルスキャンを選択:インデックスがあるのにフルスキャン
  • ネストループが選ばれる:ハッシュ結合の方が速いのに
  • 並列クエリが起動しない:行数推定が少なすぎて

IT女子 アラ美
ANALYZEって自動で実行されないんですか?毎回手動でやるの大変そうです。

ITアライグマ
autoanalyzeという機能があり、デフォルトで有効です。ただし大量データの一括投入後など、手動でANALYZEを実行すべきタイミングもありますよ。

ケーススタディ:店舗検索クエリの高速化

💡

データベース・インフラエンジニアとしてキャリアを加速させたい方へ
自社開発企業への転職で、専門性を活かしながら年収アップを実現しませんか

状況(Before)

ECサイトの店舗検索機能を担当していた時の事例です。ユーザーが現在地から半径5km以内の店舗を検索する機能で、レスポンスが10秒以上かかるという問題が発生していました。

  • 環境:PostgreSQL 15 + PostGIS 3.3、AWS RDS(db.r5.large)
  • データ量:店舗テーブル約350万件、ジオメトリカラム付き
  • 問題のクエリ:ST_DWithinを使った半径検索
  • レスポンス時間:平均12秒(ピーク時は20秒超)
  • インデックス:GiSTインデックス作成済み(のはず)

行動(Action)

まずEXPLAIN ANALYZEで実行計画を確認しました。

EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT id, name, ST_AsText(geom)
FROM shops
WHERE ST_DWithin(
  geom,
  ST_SetSRID(ST_MakePoint(139.7454, 35.6586), 4326)::geography,
  5000
);

出力を確認すると、Seq Scan(フルスキャン)になっていました。インデックスがあるのに使われていない。原因を調査したところ、以下の問題が判明しました。

  1. SRID不一致:テーブルのジオメトリはSRID 4326だが、一部データがSRID 0で投入されていた
  2. ANALYZEの未実行:大量データ投入後にANALYZEを実行していなかった
  3. geography型でのインデックス:geometry型にインデックスを張っていたが、クエリはgeography型にキャストしていた

修正内容は以下の通りです。

-- 1. SRID不一致データの修正
UPDATE shops SET geom = ST_SetSRID(geom, 4326) WHERE ST_SRID(geom) = 0;

-- 2. geography型でインデックスを再作成
DROP INDEX IF EXISTS idx_shops_geom;
CREATE INDEX idx_shops_geom_geog ON shops USING gist((geom::geography));

-- 3. ANALYZE実行
ANALYZE shops;

結果(After)

修正後、同じクエリを実行すると劇的に改善しました。

  • レスポンス時間:12秒 → 45ミリ秒(約99.6%改善)
  • 実行計画:Index Scan using idx_shops_geom_geog に変更
  • Buffer使用量:45,000ページ → 120ページに削減

「データベースの内部動作理解」がこうしたパフォーマンス問題の解決に役立ちます。mongobleedで発覚したMongoDB脆弱性記事も参考にしてください。

IT女子 アラ美
インデックスを作ったのに使われない原因が分かりました。SRIDの統一が大事なんですね。

ITアライグマ
SRIDとデータ型の不一致はよくある落とし穴です。EXPLAIN ANALYZEで実行計画を確認する習慣が早期発見につながります。

空間インデックス設計のベストプラクティス

ケーススタディで学んだ内容を一般化し、空間インデックス設計のベストプラクティスを整理します。

SRID(空間参照系)の統一

SRID(Spatial Reference System Identifier)は、座標系を識別する番号です。日本でよく使われるのは以下の通りです。

  • SRID 4326:WGS 84(GPS座標系)。緯度・経度で表現
  • SRID 6668:JGD2011(日本測地系2011)
  • SRID 32654:UTM Zone 54N(東京周辺でメートル単位の計算に便利)
-- SRIDの確認
SELECT DISTINCT ST_SRID(geom) FROM shops;

-- SRIDの統一
ALTER TABLE shops
  ALTER COLUMN geom TYPE geometry(Point, 4326)
  USING ST_SetSRID(geom, 4326);

geometry型とgeography型の使い分け

PostGISには2つの空間データ型があります。プロジェクトの要件に応じて選択しましょう。

  • geometry型:平面座標系。計算が高速だが、地球の丸みを考慮しない
  • geography型:地球楕円体上の座標。距離計算が正確だが、やや遅い

要件に応じた型選択が重要で、jotaiでReact状態管理を効率化する記事で触れた「適材適所の設計」の考え方も参考になります。

さらなる年収アップやキャリアアップを目指すなら、ハイクラス向けの求人に特化した以下のサービスがおすすめです。

比較項目 TechGo レバテックダイレクト ビズリーチ
年収レンジ 800万〜1,500万円ハイクラス特化 600万〜1,000万円IT専門スカウト 700万〜2,000万円全業界・管理職含む
技術スタック モダン環境中心 Web系に強い 企業によりバラバラ
リモート率 フルリモート前提多数 条件検索可能 原則出社も多い
おすすめ度 S技術で稼ぐならここ A受身で探すなら Bマネジメント層向け
公式サイト 無料登録する - -
IT女子 アラ美
年収を上げたいんですが、ハイクラス求人ってハードルが高そうで迷います…
ITアライグマ
技術力を武器に年収を上げたいならTechGo一択!でも、自分の市場価値を幅広くチェックしたいならビズリーチも登録しておくと安心ですよ。

まとめ

PostGISの空間インデックスとANALYZE統計情報について、実践的な視点から解説しました。本記事のポイントを振り返ります。

  • GiSTインデックス:空間データはR-Tree構造のGiSTインデックスで高速化
  • ANALYZEの重要性:統計情報が古いとプランナーが最適な実行計画を選べない
  • SRIDの統一:混在するとインデックスが効かないケースがある
  • geometry vs geography:要件に応じて適切な型を選択
  • EXPLAIN ANALYZE:問題発生時は必ず実行計画を確認

地理空間データベースのパフォーマンス問題は、表面的な対処ではなく、インデックスとプランナーの動作を理解することで根本解決できます。まずはEXPLAIN ANALYZEで現状を把握することから始めてみてください。

IT女子 アラ美
今まで「とりあえずインデックス作れば速くなる」と思っていました。奥が深いですね。

ITアライグマ
インデックスは作るだけでなく、正しく使われているかを確認することが大切です。EXPLAIN ANALYZEを習慣にすると、問題の早期発見につながりますよ。

厳しめIT女子 アラ美による解説ショート動画はこちら

この記事をシェアする
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

ITアライグマのアバター ITアライグマ ITエンジニア / PM

都内で働くPM兼Webエンジニア(既婚・子持ち)です。
AIで作業時間を削って実務をラクにしつつ、市場価値を高めて「高年収・自由な働き方」を手に入れるキャリア戦略を発信しています。

目次