Postgres比廉价索引更喜欢昂贵的ST_Intersects()

时间:2015-02-20 16:37:14

标签: sql postgresql openstreetmap postgis

我正在使用Postgres 9.4对OSM的完整行星转储执行相当简单的查询。我想要做的就是获取属于德国A8高速公路的所有方式。在准备步骤中,我为所有管理边界关系创建了多个多边形,并将它们存储在表格多边形中,这样我就可以进行更简单的空间相交测试。为了实现快速查询处理,我还为' ref'创建了索引。 hstore标签:

CREATE INDEX idx_ways_tags_ref ON planet_20141222.ways USING btree (lower(tags->'ref'));

此外,我已经通过先前的查询获得了德国行政边界的id(结果id = 51477)。

我的db模式是普通的API 0.6模式,数据通过转储方法导入Postgres(使用渗透性附带的pgsnapshot_schema_0.6 * .sql脚本)。还对所有表进行了真空分析。

有问题的查询如下所示:

SELECT DISTINCT wy.id FROM planet_20141222.ways wy, planet_20141222.polygons py
WHERE py.id=51477 AND ST_Intersects(py.geom,wy.linestring) AND ((wy.tags->'highway') is not null) AND (lower(wy.tags->'ref') like lower('A8'));

这个查询的运行时很糟糕,因为Postgres更喜欢昂贵的ST_Intersects()测试,而不是反对' ref'上的廉价(和高选择性)索引。删除交集测试时,查询将在几毫秒内返回。

我能做些什么才能使Postgres首先评估查询中存在索引的部分,而不是测试整个星球上与德国交汇的每一条路?

我目前的解决方案是在两个单独的查询中拆分SQL查询。第一个是索引支持的标签测试,第二个是空间相交测试。我想Postgres可以做得更好,但是怎么做?

编辑:

a)OSM 0.6导入脚本在路径表上创建以下索引:

CREATE INDEX idx_ways_bbox ON ways USING gist (bbox);
CREATE INDEX idx_ways_linestring ON ways USING gist (linestring);

b)另外,我在多边形上创建了另一个索引:

CREATE INDEX polygons_geom_tags on polygons using gist(geom, tags);

c)查询没有 ST_Intersects()的EXPLAIN ANALYZE输出如下所示:

"Index Scan using ways_tags_ref on ways  (cost=0.57..4767.61 rows=1268 width=467) (actual time=0.064..0.267 rows=60 loops=1)"
"  Index Cond: (lower((tags -> 'ref'::text)) = 'a8'::text)"
"  Filter: (((tags -> 'highway'::text) IS NOT NULL) AND (lower((tags -> 'ref'::text)) ~~ 'a8'::text))"
"  Rows Removed by Filter: 5"
"Total runtime: 0.300 ms"

使用ST_Intersects()的查询的运行时间超过15分钟,所以我取消了它。

1 个答案:

答案 0 :(得分:1)

也许尝试这样的事情......?

WITH wy AS (
  SELECT * FROM planet_20141222.ways 
  WHERE ((tags->'highway') IS NOT null)
  AND (lower(tags->'ref') LIKE lower('A8'))
)
SELECT DISTINCT wy.id 
FROM wy, planet_20141222.polygons py
WHERE py.id=51477 
  AND ST_Intersects(py.geom,wy.linestring);