我已经阅读了很多帖子,讨论了使用INNER JOIN和WHERE的优点。我发现的解释似乎都表明INNER JOIN的偏好更多地与可读性相关而不是功能性。但是,在应用这两种方法重新计算几何字段时,我在计算时间方面遇到了巨大的差异。
在下面的示例中,point_geoms.point_within字段是相同类型的几何类型字段,SRID为“POINTS”.geom
例如,这个WHERE版本几乎立即在~5k记录的子集上运行:
UPDATE "POINTS"
SET geom = point_geoms.point_within
FROM point_geoms
WHERE "POINTS"."POINT_ID" = point_geoms.point_id
虽然这个INNER JOIN版本会继续旋转,即使被要求只计算一行:
UPDATE "POINTS"
SET geom = p.point_within
FROM "POINTS" s
INNER JOIN point_geoms p
ON s."POINT_ID" = p.point_id
当我基于相同的INNER JOIN进行SELECT时,它会相当快地返回子集中的所有〜5k记录...这让我更加困惑INNER JOIN更新为什么只是一直旋转。当我解析选择版本时,看起来它只扫描point_geoms表中的~5k行,但是当更新它时,看起来它想要扫描“POINTS”表中的所有〜1M +。
任何想法/解释都将不胜感激。也许我刚刚在这里做了些蠢事。无论哪种方式,都非常想了解最新情况。提前谢谢!
答案 0 :(得分:0)
由于UPDATE
的工作方式,INNER JOIN
版本包含"POINTS"
及其别名s
之间不受限制的自我加入,所以有很多(!)更多行更新。更糟糕的是,每个目标行有多个输出行需要更新,因此,如果您等到UPDATE
完成后,您将获得不确定的结果。
UPDATE
FROM
条款与SELECT
查询的条款完全相同,因为UPDATE
&#39}目标表("POINTS"
)包含在内而没有明确提及。见the PostgreSQL Docs,其中说:
当存在FROM子句时,实质上发生的是目标表连接到from_list中提到的表,并且连接的每个输出行表示目标表的更新操作。使用FROM时,应确保连接为每个要修改的行生成最多一个输出行。换句话说,目标行不应该与其他表连接到多个行。如果是,那么只有一个连接行将用于更新目标行,但是将使用哪一个不容易预测。
由于这种不确定性,仅在子选择内引用其他表更安全,但通常比使用连接更难阅读和更慢。
当第二个查询引入FROM "POINTS" s
行时,它会有效地从CROSS JOIN
创建"POINTS"
到自身。请注意EXPLAIN
输出如何包含2个序列扫描:一个用于"POINTS"
,另一个用于其别名"POINTS" s
:
postgres=# EXPLAIN UPDATE "POINTS"
SET geom = p.point_within
FROM "POINTS" s
INNER JOIN point_geoms p
ON s."POINT_ID" = p.point_id;
QUERY PLAN
------------------------------------------------------------------------------------------------
Update on "POINTS" (cost=140.50..62539765.00 rows=5000000000 width=28)
-> Nested Loop (cost=140.50..62539765.00 rows=5000000000 width=28)
-> Seq Scan on "POINTS" (cost=0.00..15406.00 rows=1000000 width=10)
... snip ...
-> Seq Scan on "POINTS" s (cost=0.00..15406.00 rows=1000000 width=10)
此更新的输出行数为5,000,000,000,如果更新完成,更新后的值将是不确定的,即垃圾。
另一个版本完全不同,只生成5,000个输出行 这个过程。它不仅更快,而且可能是预期的。
据我所知,在制作INNER JOIN
时,无法直观地使用UPDATE
语法。我希望这可以帮助您了解正在发生的事情。