我正在使用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分钟,所以我取消了它。
答案 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);