我正在使用OpenStreetMap osm2pgsql数据库。其中一个表(planet_osm_line)有两个索引字段:osm_id(int,primary key)和way(postgis geometry)。
我想找到哪条街道与特定的街道相交,我知道它是osm_id。所以我这样做:
SELECT name, * FROM planet_osm_line
WHERE highway IS NOT NULL
AND osm_id != 126021312
AND ST_Intersects(way, (SELECT way FROM planet_osm_line WHERE osm_id = 126021312 LIMIT 1))
运行大约需要10秒钟。
如果相反,我将该子查询取出并单独运行,它看起来像这样:
SELECT name, * FROM planet_osm_line
WHERE highway IS NOT NULL
AND osm_id != 126021312
AND ST_Intersects(way, '010200002031BF0D000D000000E17...')
运行大约需要0.47秒。
在第一个和第二个查询上运行EXPLAIN会给我一个关于差异的提示。
首先:
Seq Scan on planet_osm_line (cost=2.09..614596.67 rows=628706 width=1079)
Filter: ((highway IS NOT NULL) AND (osm_id <> 126021312) AND st_intersects(way, $0))
InitPlan 1 (returns $0)
-> Limit (cost=0.43..2.09 rows=1 width=249)
-> Index Scan using planet_osm_line_pkey on planet_osm_line planet_osm_line_1 (cost=0.43..3.76 rows=2 width=249)
Index Cond: (osm_id = 126021312)
第二
Index Scan using planet_osm_line_index on planet_osm_line (cost=0.41..4.25 rows=1 width=1079)
Index Cond: (way && '010200002031BF0D000D000000E17...'::geometry)
Filter: ((highway IS NOT NULL) AND (osm_id <> 126021312) AND _st_intersects(way, '010200002031BF0D000D000000E17...'::geometry))
为什么PostgreSQL第一次进行seq扫描而第二次进行索引扫描?有没有办法解决这个问题而不发出两个查询?
答案 0 :(得分:2)
重写你的查询,这样你就不会在ST_Intersects中有一个子查询,而是在FROM中有一个交叉连接,然后由WHERE中的交叉点限制(这也隐含了一个&amp;&amp;,即,边界框检查,它将击中空间索引)。
SELECT name, osm.*
FROM planet_osm_line osm,
(SELECT way FROM planet_osm_line WHERE osm_id = 126021312 LIMIT 1) line
WHERE highway IS NOT NULL
AND osm_id != 126021312
AND ST_Intersects(osm.way, line.way);
答案 1 :(得分:1)
这种方式似乎工作正常(部分回答我的问题):
SELECT l1.name, l1.*
FROM planet_osm_line AS l1
INNER JOIN planet_osm_line AS l2
ON ST_Intersects(l1.way, l2.way)
WHERE l1.highway IS NOT NULL
AND l1.osm_id != 126021312
AND l2.osm_id = 126021312
它的说明显示PostgreSQL似乎首先做了我想做的事情:
Nested Loop (cost=6.80..577.98 rows=7451 width=1108)
-> Index Scan using planet_osm_line_pkey on planet_osm_line l2 (cost=0.43..3.76 rows=2 width=249)
Index Cond: (osm_id = 126021312)
-> Bitmap Heap Scan on planet_osm_line l1 (cost=6.37..286.48 rows=63 width=1108)
Recheck Cond: (way && l2.way)
Filter: ((highway IS NOT NULL) AND (osm_id <> 126021312) AND _st_intersects(way, l2.way))
-> Bitmap Index Scan on planet_osm_line_index (cost=0.00..6.36 rows=206 width=0)
Index Cond: (way && l2.way)
我仍然很好奇为什么第一个查询的行为不像这个。