【问题标题】:Optimizing a Large PostGIS Query优化大型 PostGIS 查询
【发布时间】:2014-06-30 21:35:02
【问题描述】:

我目前有一个大表 mivehdetailedtrajectory(25B 行)和一个小表 cell_data_tower(400 行),我需要使用 PostGIS 加入它们。具体来说,我需要运行这个查询:

SELECT COUNT(traj.*), tower.id
FROM cell_data_tower tower LEFT OUTER JOIN mivehdetailedtrajectory traj
ON ST_Contains(tower.geom, traj.location)
GROUP BY tower.id
ORDER BY tower.id;

它因为无法写入磁盘而愤怒地出错。这对于 SELECT 来说似乎很奇怪,所以我运行了 EXPLAIN: 注意:gserialized_gist_joinsel:不支持连接类型 1

                                                     QUERY PLAN                                                     
--------------------------------------------------------------------------------------------------------------------
 Sort  (cost=28905094882.25..28905094883.25 rows=400 width=120)
   Sort Key: tower.id
   ->  HashAggregate  (cost=28905094860.96..28905094864.96 rows=400 width=120)
         ->  Nested Loop Left Join  (cost=0.00..28904927894.80 rows=33393232 width=120)
               Join Filter: ((tower.geom && traj.location) AND _st_contains(tower.geom, traj.location))
               ->  Seq Scan on cell_data_tower tower  (cost=0.00..52.00 rows=400 width=153)
               ->  Materialize  (cost=0.00..15839886.96 rows=250449264 width=164)
                     ->  Seq Scan on mivehdetailedtrajectory traj  (cost=0.00..8717735.64 rows=250449264 width=164)

我不明白为什么 postgres 认为它​​应该实现内部表。另外,老实说,我总体上不了解该计划。似乎它应该将 cell_data_tower 表保留在内存中并遍历 mivehdetailedtrajectory 表。关于如何优化它以(a)运行,(b)在合理的时间内这样做的任何想法。具体来说,这似乎应该可以在不到 1 天的时间内完成。

编辑:Postgres 9.3 版

【问题讨论】:

  • 请添加 PostgreSQL 版本。
  • 可能是一个愚蠢的问题,但你确实有关于 mivehdetailedtrajectory 的空间索引?在这种查询中,您实际上并不需要编写左外连接,因为本质上无论如何您都在进行完全连接,但通过“空间”连接来限制结果。如果您用逗号替换左外连接,您可能会得到不同的方案。
  • 我也遇到过类似的问题,即使用哈希连接耗尽磁盘空间。您可以尝试设置 enable_hashagg=off 和/或 enable_hashjoin=off。这似乎会使查询计划变得更糟(确实如此),但它会切换到使用嵌套循环连接,虽然速度较慢,但​​不会占用磁盘空间。最终,如果您没有空间索引,那么无论如何您都在进行双循环,并且每次都检查 ST_Contains。正如 Jakub 指出的那样,我冒昧地将 tower.id 添加到您的选择中。
  • 我在 mivehdetailedtrajectory 上有一个空间索引。问题似乎与 25B 行有关,没有什么是合理的。也许我需要开始寻找更适合我正在处理的数据规模的东西。
  • @SteveY。是的,250 亿对于 Postgres 查询来说是相当大的。您的 cell_data_tower 几何图形本质上是圆形的吗?因为,如果是这样,很容易将包含重写为简单的欧几里德距离计算,这将使这非常适合 map-reduce,此时您可以开始考虑 Hadoop(或类似的东西)。

标签: postgresql postgis


【解决方案1】:

需要大量内存的查询是那些相关子查询性能更好的罕见地方(LATERAL JOIN 也应该可以工作,但这些超出了我的范围)。另请注意,您没有选择 tower.id,因此您的结果不会太有用。

SELECT tower.id, (SELECT COUNT(traj.*) 
                  FROM mivehdetailedtrajectory traj
                  WHERE ST_Contains(tower.geom, traj.location))
FROM cell_data_tower tower
ORDER BY tower.id;

首先尝试使用LIMIT 1 运行它。总运行时间应该是一个塔的运行时间 * 塔的数量。

【讨论】:

    【解决方案2】:

    我没有你这么大的db,只有80M。但在我的情况下,我创建了一个 LinkID 字段来了解每个几何图形的位置,并在我插入新记录时计算哪个是最接近的 LinkID。

    当我发现单个 LinkID 需要 30 毫秒,而执行 80M 次需要 27 天时,我从预先计算这些值开始。

    我也不保留所有记录,我只保留一个月。

    【讨论】:

      猜你喜欢
      • 2015-09-17
      • 1970-01-01
      • 2013-02-18
      • 1970-01-01
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多