【发布时间】: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