2014-10-29 70 views
0

我讀過很多討論使用INNER JOIN vs WHERE的優點的帖子。我發現的所有解釋似乎都表明,INNER JOIN的偏好與可讀性有關的多於功能。但是,在應用這兩種方法重新計算幾何字段時,我在計算時間方面遇到了很大的差異。對於Geom字段Recalc是WHERE還是INNER JOIN首選?

在下面的例子中,point_geoms.point_within字段是相同的類型和SRID作爲「點」 .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 

當我SEL ECT基於完全相同的INNER JOIN,它會相當快地返回子集中的所有〜5k條記錄。這使我更加困惑,因爲INNER JOIN更新只是旋轉着。當我解釋選擇版本時,它看起來像它只掃描point_geoms表中的〜5k行,但是當更新時它看起來像要掃描「POINTS」表中的所有〜1M +。

任何想法/解釋將不勝感激。也許我在這裏做了一些愚蠢的事情。無論哪種方式,真的想知道發生了什麼事情。先謝謝你!

回答

0

因爲這樣UPDATE作品中,INNER JOIN版本包括"POINTS"和它的別名s之間的無限制自連接,所以有很多(!)更行更新。更糟糕的是,每個目標行都有多個輸出行需要更新,因此,如果您等待完成UPDATE,您會得到一個不確定的結果。

UPDATEFROM條款是不太一樣的,對於一個SELECT查詢,因爲UPDATE的目標表("POINTS")包括沒有明確提及。見the PostgreSQL Docs,該說:

當FROM子句,什麼本質上發生的事情是目標表連接到在from_list提到的表,和聯接每個輸出行代表一個更新操作目標表。使用FROM時,應確保該連接爲每個要修改的行生成至多一個輸出行。換句話說,目標行不應該連接到其他表中的多行。如果是這樣,那麼只有其中一個連接行將用於更新目標行,但哪一個將被使用並不容易預測。

由於這種不確定性,僅在子選擇內引用其他表更安全,雖然通常難以閱讀並且比使用聯接更慢。

當第二查詢介紹FROM "POINTS" s線,它有效地產生從"POINTS"一個CROSS JOIN到其自身上。注意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) 

輸出行此更新的數50億,而更新的值會,如果更新曾經完成,是不確定的,即垃圾。

其他版本做了一些完全不同的事情,並且只在 過程中產生5,000個輸出行。它不僅更快,而且可能是預期的。

據我所知,在製作UPDATE時,不可能直觀地使用INNER JOIN語法。我希望這可以幫助你理解正在發生的事情。