PostGIS 空间索引为什么没生效?EXPLAIN、ST_Intersects 与范围过滤排查

编程与开发
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

问题场景:建了 GiST 索引,查询为什么还是慢

PostGIS 空间查询慢时,很多人会先确认是否创建了 GiST 索引。索引确实重要,但它不是魔法开关。查询写法不合适、在字段上临时做 ST_Transform、统计信息过旧、返回数据比例太高,都可能让优化器放弃索引或索引收益很低。

排查空间索引问题,不能只看“有没有索引”,而要看执行计划。EXPLAIN ANALYZE 是判断数据库实际怎么执行查询的关键工具。

先确认索引和统计信息

CREATE INDEX idx_parcels_geom
ON parcels
USING GIST (geom);

ANALYZE parcels;

创建索引后应更新统计信息。对于频繁导入、删除或批量更新的数据表,统计信息过旧会影响优化器判断。

用 EXPLAIN 看执行计划

EXPLAIN ANALYZE
SELECT p.*
FROM parcels p
JOIN roads r
ON ST_Intersects(p.geom, r.geom);

如果计划中出现 Index Scan 或 Bitmap Index Scan,说明索引参与了查询。如果大量 Seq Scan 且表很大,就需要检查查询条件和数据分布。

避免在索引字段上包函数

常见错误是这样写:

ST_Intersects(ST_Transform(p.geom, 3857), r.geom)

对索引字段临时转换,会让数据库难以直接使用原字段上的索引。更稳的做法是让数据提前统一 CRS,或把查询参数转换到表的 CRS。高频接口可以增加投影后的几何字段并单独建索引。

写法 索引友好程度 建议
ST_Intersects(geom, param_geom) 推荐
ST_Transform(geom) 避免用于高频查询
无范围条件的大结果查询 不稳定 增加 bbox 或分页

空间谓词与范围过滤

ST_Intersects 等常见谓词通常会利用边界框过滤。但在复杂 SQL 中,可以显式加入 && 作为候选范围过滤,再做精确判断。这样执行计划更清晰,也方便调优。

项目避坑:索引不等于少返回数据

如果查询条件会命中表中大部分要素,走索引未必更快。索引适合快速缩小候选集,不适合替代合理的数据范围和业务过滤条件。

WebGIS 接口应尽量按地图视窗、图层级别、行政区或业务条件过滤,不要一次返回全城所有几何。

FAQ

为什么小表不走空间索引?

表很小时,全表扫描可能比索引更便宜,这是正常优化器选择。

ST_Intersects 一定会用索引吗?

不一定。是否使用索引取决于执行计划、数据量、统计信息和查询写法。

空间索引能加速面积计算吗?

索引主要加速空间过滤。对已选中的大量复杂几何做面积计算,仍然需要计算成本。

总结

PostGIS 性能优化要从执行计划出发。索引、SQL 写法、CRS 统一、统计信息和返回数据量共同决定速度。先用 EXPLAIN 找瓶颈,再改查询,才是真正有效的优化。