Postgresql 找到1000个点周围30米正方形内的所有街道段。尽可能快地做

Postgresql 找到1000个点周围30米正方形内的所有街道段。尽可能快地做,postgresql,Postgresql,我有一个使用PostgreSQL的快速解决方案。我还有一个8.75倍快的解决方案,使用自定义数据库和自定义索引 定制解决方案正在发挥作用:下一步是在整个北美实施它。然而,我想确保我没有过度关注同样快(或更快)的PostgreSQL解决方案 解决方案必须返回每个点周围30平方米范围内的所有街道段。但是,如果出于速度的考虑,它还返回一些位于稍大的广场内的街道段,例如37.5米的广场,这是可以接受的。(我的自定义解决方案之所以这样做,是因为它使用了镶嵌瓷砖) 我提出的最好的Postgres解决方案是创

我有一个使用PostgreSQL的快速解决方案。我还有一个8.75倍快的解决方案,使用自定义数据库和自定义索引

定制解决方案正在发挥作用:下一步是在整个北美实施它。然而,我想确保我没有过度关注同样快(或更快)的PostgreSQL解决方案

解决方案必须返回每个点周围30平方米范围内的所有街道段。但是,如果出于速度的考虑,它还返回一些位于稍大的广场内的街道段,例如37.5米的广场,这是可以接受的。(我的自定义解决方案之所以这样做,是因为它使用了镶嵌瓷砖)

我提出的最好的Postgres解决方案是创建一个返回所有1000个解决方案的查询。它看起来像下图,但涵盖了所有1000点。(每个ST_MakeEnvelope围绕每个点创建30米的正方形)

我以编程方式创建查询,并使用ODBC将其传递给Postgres

在我的电脑上,这个查询在一秒钟内返回1022个职位的结果。在同一台计算机上,自定义数据库加上自定义索引在一秒钟内返回8940个位置的结果


请告诉我如何写(一个可能复杂的)Postgres查询,同样快或更快

长话短说,您可以在CTE中考虑所有信封,然后让引擎根据道路查询它们

WITH cte (pos, geom) AS (select * from (values (0, ST_MakeEnvelope(64666.5,64666.5,64667.5,64667.5, 4326))
,(1, ST_MakeEnvelope(87392.5,87392.5,87393.5,87393.5, 4326))
,(2, ST_MakeEnvelope(69426.5,69426.5,69427.5,69427.5, 4326))
,(3, ST_MakeEnvelope(71599.5,71599.5,71600.5,71600.5, 4326))
,(4, ST_MakeEnvelope(45573.5,45573.5,45574.5,45574.5, 4326))
  ) as foo) SELECT pos,roads.* FROM roads,cte WHERE ST_Intersects(loc, cte.geom);
在我的机器上,6000结果为250ms


更多细节

在您的查询中,planner执行以下操作

SELECT 0 AS position, loc FROM roads WHERE ST_Intersects(ST_MakeEnvelope(-0.5,-0.5,0.5,0.5, 4326), loc)
UNION ALL 
SELECT 1 AS position, loc FROM roads WHERE ST_Intersects(ST_MakeEnvelope(0.5,0.5,1.5,1.5, 4326), loc);

 Append  (cost=6.07..167.19 rows=170 width=36)
   ->  Bitmap Heap Scan on roads  (cost=6.07..82.75 rows=85 width=36)
         Recheck Cond: ('...'::geometry && loc)
         Filter: _st_intersects('...'::geometry, loc)
         ->  Bitmap Index Scan on roads_loc_index  (cost=0.00..6.05 rows=254 width=0)
               Index Cond: ('...'::geometry && loc)
   ->  Bitmap Heap Scan on roads roads_1  (cost=6.07..82.75 rows=85 width=36)
         Recheck Cond: ('...'::geometry && loc)
         Filter: _st_intersects('...'::geometry, loc)
         ->  Bitmap Index Scan on roads_loc_index  (cost=0.00..6.05 rows=254 width=0)
               Index Cond: ('...'::geometry && loc)
(11 rows)
请注意道路上的位图堆扫描。我要强调的不是位图堆扫描,而是位置越多越好。所以,我们的想法是让规划者按照自己的意愿“迭代”道路,而不是告诉他将所有道路都联合起来

现在请注意,通过使用(对于4000个位置)

这也会影响查询,响应时间为538ms。我们甚至不与道路相交,只是创建cte的速度很慢


结论当使用自定义值填充
CTE
时,避免使用
UNION ALL
,只需声明带有
值的所有行

,如果您只查询一个城市,您确定规划师使用您的索引几何方式吗?我没有测试过它,但对于较旧的postgis,您需要特殊语法才能使用索引。我已验证是否正在使用geom_way列的索引。pgAdmin中的“解释”面板显示,首先使用&&运算符,以便查找其边界框内包含该点的所有线段。然后通过_st_intersects函数对结果进行过滤,该函数只选择与我提供的包络线实际相交的线段。
SELECT 0 AS position, loc FROM roads WHERE ST_Intersects(ST_MakeEnvelope(-0.5,-0.5,0.5,0.5, 4326), loc)
UNION ALL 
SELECT 1 AS position, loc FROM roads WHERE ST_Intersects(ST_MakeEnvelope(0.5,0.5,1.5,1.5, 4326), loc);

 Append  (cost=6.07..167.19 rows=170 width=36)
   ->  Bitmap Heap Scan on roads  (cost=6.07..82.75 rows=85 width=36)
         Recheck Cond: ('...'::geometry && loc)
         Filter: _st_intersects('...'::geometry, loc)
         ->  Bitmap Index Scan on roads_loc_index  (cost=0.00..6.05 rows=254 width=0)
               Index Cond: ('...'::geometry && loc)
   ->  Bitmap Heap Scan on roads roads_1  (cost=6.07..82.75 rows=85 width=36)
         Recheck Cond: ('...'::geometry && loc)
         Filter: _st_intersects('...'::geometry, loc)
         ->  Bitmap Index Scan on roads_loc_index  (cost=0.00..6.05 rows=254 width=0)
               Index Cond: ('...'::geometry && loc)
(11 rows)
WITH cte (pos, geom) AS ( SELECT 0, ST_MakeEnvelope(5687.5,5687.5,5688.5,5688.5, 4326)
 UNION ALL 
SELECT 1, ST_MakeEnvelope(13717.5,13717.5,13718.5,13718.5, 4326)
 UNION ALL 
SELECT 2, ST_MakeEnvelope(53009.5,53009.5,53010.5,53010.5, 4326)
 UNION ALL 
SELECT 3, ST_MakeEnvelope(60566.5,60566.5,60567.5,60567.5, 4326)
 UNION ALL 
SELECT 4, ST_MakeEnvelope(17843.5,17843.5,17844.5,17844.5, 4326) ) SELECT pos FROM cte;