GIS開発研究所 > PostGISのST_Intersectsが遅い原因|GiSTインデックスの確認

PostGISのST_Intersectsが遅い原因|GiSTインデックスの確認

2026年7月29日

6分で読めます

PostGISのST_Intersectsが遅いときに、GiST空間インデックス、実行計画、SRID、巨大ポリゴン、事前絞り込みを順番に確認する方法を解説します。EXPLAIN ANALYZEの読み方と、本番で性能劣化を再発させない監視項目をSQL例付きで紹介します。

PostGIS
ST_Intersects
GiST
空間インデックス

PostGISでポイントと行政区域を重ねたり、設備が対象エリア内にあるか判定したりするとき、よく使うのがST_Intersectsです。数千件では問題なかったSQLが、数十万件に増えた途端に何分もかかることがあります。

そんなときは、SQLを複雑に書き換える前に、空間インデックスがあり、実際の検索で使われているかを確認しましょう。

先に結論:ST_Intersectsが遅いときの確認順

次の順番で切り分けると、原因を見つけやすくなります。

  1. geometry列にGiSTインデックスがあるか
  2. EXPLAIN (ANALYZE, BUFFERS)でインデックスが使われているか
  3. 比較するgeometryのSRIDがそろっているか
  4. 絞り込み条件を空間検索より前に減らせるか
  5. 1件だけ極端に複雑なポリゴンがないか

PostGIS公式では、空間検索を速くするにはGiSTインデックスを作り、インデックス対応の空間関数を使う必要があると説明されています。ST_Intersectsはインデックス対応関数の1つです。

GiST空間インデックスを確認する

まず、対象テーブルのインデックスを確認します。

SELECT
  indexname,
  indexdef
FROM pg_indexes
WHERE schemaname = 'public'
  AND tablename = 'assets';

geometry列geomにGiSTインデックスがなければ、次のように作成します。

CREATE INDEX CONCURRENTLY assets_geom_gix
  ON public.assets
  USING GIST (geom);

CONCURRENTLYを使うと、通常のインデックス作成より書き込みを止めにくくできます。ただし、トランザクション内では実行できず、処理時間も長くなることがあります。本番ではデータ量と実行時間を確認してください。

作成後は統計情報を更新します。

ANALYZE public.assets;

EXPLAINでST_Intersectsの実行計画を見る

インデックスがあっても、検索条件やデータ分布によって使われない場合があります。実際のSQLにEXPLAINを付けます。

EXPLAIN (ANALYZE, BUFFERS)
SELECT a.id
FROM assets a
JOIN management_areas m
  ON ST_Intersects(a.geom, m.geom)
WHERE m.id = 10;

実行計画で確認したい言葉は次のとおりです。

  • Index ScanBitmap Index Scanがあるか
  • geometry列のGiSTインデックス名が出ているか
  • Seq Scanで全件を読んでいないか
  • 推定行数と実際の行数が大きくずれていないか
  • 読み込んだバッファ数が極端に多くないか

小さなテーブルでは、インデックスより全件走査の方が速いと判断されることもあります。Seq Scanが出ただけで異常と決めつけず、実行時間と行数を一緒に見ましょう。

ST_Intersectsの前に通常条件で対象を減らす

空間検索の対象が全年度・全地域に広がっていると、不要な比較が増えます。業務上の条件を先に入れます。

SELECT a.id
FROM assets a
JOIN management_areas m
  ON ST_Intersects(a.geom, m.geom)
WHERE m.id = 10
  AND a.status = 'active'
  AND a.surveyed_at >= DATE '2026-01-01';

statussurveyed_atにも検索が多いなら、通常のB-treeインデックスを検討します。

CREATE INDEX CONCURRENTLY assets_status_surveyed_at_idx
  ON assets (status, surveyed_at);

ただし、インデックスを増やしすぎると更新処理が重くなります。実際に使う検索条件へ絞りましょう。

SRIDとgeometry型を確認する

比較する2つのレイヤーでSRIDが異なると、そのままでは空間演算できません。列定義とデータを確認します。

SELECT
  ST_SRID(geom) AS srid,
  GeometryType(geom) AS geometry_type,
  count(*)
FROM assets
GROUP BY ST_SRID(geom), GeometryType(geom);

検索のたびにST_Transformをかけると、条件によっては列側のインデックスを使いにくくなります。よく使う座標系に保存時点で統一するか、変換後geometryへ式インデックスを作る方法を検討します。

巨大ポリゴンでST_Intersectsが遅い場合

頂点数が非常に多い都道府県境界、海岸線、管理区域などは、候補が絞られた後の厳密判定にも時間がかかります。

まず頂点数を確認します。

SELECT
  id,
  ST_NPoints(geom) AS point_count
FROM management_areas
ORDER BY point_count DESC
LIMIT 20;

用途によっては、表示用に簡略化したgeometryを別に持つ、またはST_Subdivideで分割した検索用テーブルを用意します。原本geometryを直接上書きせず、検索用データとして分けると安全です。

よくある改善ミス

&&だけに置き換える

&&は外接矩形が重なるかを調べるため、厳密な交差判定とは結果が異なります。候補抽出には使えますが、業務判定にはST_Intersectsなどの正確な条件が必要です。

すべてのSQLにST_Transformを追加する

SRIDの不一致を隠せても、毎回の座標変換が負担になります。入力時のSRID、保存するSRID、表示時のSRIDを整理しましょう。

本番でいきなりVACUUM FULLを実行する

VACUUM FULLはテーブルを書き換え、強いロックが発生します。まず通常のVACUUM (ANALYZE)、統計、インデックス、SQLを確認します。

本番運用で再発を防ぐ

データは毎月増えるため、改善時点の実行時間だけで終わらせないことが大切です。

  • 代表的な空間SQLの実行時間を記録する
  • レコード数と頂点数の増加を確認する
  • インポート後にANALYZEを実行する
  • 長時間クエリをpg_stat_statementsで確認する
  • 表示用・分析用・編集用のgeometryを分ける

ST_Intersectsの性能は、関数だけではなく、インデックス、データ量、ポリゴンの複雑さ、絞り込み条件で決まります。

PostGISの空間検索や大規模GISデータの性能改善でお困りの場合は、GIS開発を無料相談する

参考資料

GISシステム開発・改善支援

既存GISの改善から新規開発まで相談できます

QGIS、PostGIS、GeoServer、MapLibre、GeoDjangoを使った現地調査基盤、Web地図、データ処理を支援します。

GIS開発の無料相談

同期・性能・地図表示の問題を相談できます

QGIS、PostGIS、GeoServer、MapLibre、GeoDjangoの構成を確認し、原因の切り分けと改善順を整理します。

著者
守高 成悟
守高 成悟

代表取締役 CEO

千葉県出身。10歳の頃からプログラミングを始め、ゲーム、Webサイト、ロボット、スマホアプリなどを制作。大阪大学基礎工学部情報科学科で情報工学と統計学を学び、大学時代はAIを研究。大学在学中にWeb広告代理店でのインターンや人材系Webサービスの立ち上げを経験し、卒業後はフリーランスエンジニアとしてGISシステム、データ基盤構築、Webシステムの開発に従事。10年以上のWebアプリ開発・データ分析経験を基に、2023年9月に株式会社ビットライトを設立し、現場業務の仕組み化からデータ基盤構築、データ活用支援までを一気通貫で支援。

運営会社
株式会社ビットライト
株式会社ビットライト

顧客が本当に必要だった価値を、実装する。

現場業務の仕組み化からデータ基盤構築、データ活用支援までを一気通貫で支援しています。

コーポレートサイトを見る