【问题标题】:PostgreSQL - very slow table join on OSM dataPostgreSQL - OSM 数据上非常慢的表连接
【发布时间】:2016-07-07 20:39:36
【问题描述】:

我在创建表连接时遇到问题。查询永远运行。我在一张表中打开了街道地图自行车路线,其中包含所有属性。

Table planet_osm_line
osm_id bigint,
route text,
name text,
network text,
osmc_color text,
reversed text,
state text,
"instance:cycle" text,
"relation:id" text,
ref text,
description text,
distance text,
tags hstore,
way geometry(LineString,900913)

有些行是重复的(单程有 2 条或多条路线),所以我将唯一的行过滤到另一个表中,并尝试将它们与来自 planet_osm_line 的数据合并:

DROP TABLE  IF EXISTS  public.bicycle_merge;
CREATE TABLE public.bicycle_merge AS

WITH singleRow as ( 
   select count(way), way
   from planet_osm_line 
   WHERE route IN ('bicycle')
   group by way
   having count(way) = 1
)
SELECT P.*
FROM planet_osm_line P
JOIN singleRow S
  ON P.way = S.way
;

这个查询永远运行......请原谅我的新手问题,但我做错了什么?

"Nested Loop  (cost=28767.43..172920474.87 rows=5892712 width=335)"
"  Join Filter: (p.way = s.way)"
"  CTE singlerow"
"    ->  GroupAggregate  (cost=27040.24..28767.43 rows=76764 width=218)"
"          Filter: (count(planet_osm_line1.way) = 1)"
"          ->  Sort  (cost=27040.24..27232.15 rows=76764 width=218)"
"                Sort Key: planet_osm_line1.way"
"                ->  Seq Scan on planet_osm_line1  (cost=0.00..4543.55     rows=76764 width=218)"

Planet_osm_line 表有大约 70.000 行。独特的几何形状约为 50.000。 此查询适用于一小组数据,但现在我正在处理整个国家(波兰)的自行车路线。非常感谢您!

【问题讨论】:

  • group by way having count(way) = 1 基本上什么都不做,你可以select distinct way from planet_osm_line。但这不需要使用 CTE,它作为优化障碍,所以你可以只使用 SELECT DISTINCT ON (way) * FROM planet_osm_line WHERE route = 'bicycle' ORDER BY way
  • 这确实有效,但它也列出了有重复的行。我想避免这种情况。我需要只存在于表中的行。
  • 哪个定义了重复? distinct on (way) 应该删除具有相同 way 列的多行。或者您想删除所有重复的行(而不仅仅是除一个之外的所有行)?
  • 有时有两种方式具有完全相同的几何形状但具有不同的属性。我只是检查了一下,查询留下了这些几何图形,但可能只遇到了第一个。
  • 这个连接实际上完成了什么?连接与嵌套循环失控,该查询中出现问题

标签: postgresql openstreetmap postgis


【解决方案1】:

您正在加入两个简单的几何图形。这意味着您正在对所有可能的匹配项之间的几何图形进行逐字节的二进制比较。这确实需要很长时间。在您的EXPLAIN ANALYZE 中,CTE 的成本为 28,767;联接是 6,000 倍

相反,您应该测试两个几何图形是否相互接触(由于 OSM 已正确地理编码,您可以假设没有线交叉点):

WITH singleRow AS ( 
   SELECT count(way), way
   FROM planet_osm_line 
   WHERE route IN ('bicycle')
   GROUP BY way
   HAVING count(way) = 1
)
SELECT P.*
FROM planet_osm_line P
JOIN singleRow S ON ST_Contains(P.way, S.way);

在您这样检索的一组行上,您可以应用函数ST_MakeLine() 将较小的行实际合并为一个。

【讨论】:

  • 很好的答案。我实际上将 ST_Touches 更改为 ST_Contains 并且效果很好。 ST_Touches 不能正常工作,但还是谢谢你 :)
  • 我的查询耗时 14 秒。这是非常可以接受的。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 2010-09-21
  • 2015-01-05
  • 1970-01-01
  • 2013-07-22
  • 2019-07-26
相关资源
最近更新 更多