Presto 原理 | Presto 中支持的七種 Join 類型
幾乎所有眾所周知的數(shù)據(jù)庫都支持以下五種類型的 JOIN 操作:Cross Join, Inner Join, Left Join, Right Join 以及 Full Join。另外,Presto 內(nèi)部還有兩種類型的 JOIN 操作:Semi Join 和 Anti Join。本文從使用者的角度介紹了這七種類型的 JOIN。
Cross Join
Cross Join 返回兩張表的笛卡爾積,其 JOIN 過程不帶任何條件。換句話說,左表中的每一行都將與右表中的每一行連接起來。Cross Join 比其他類型的聯(lián)接更昂貴,因為它在兩個表之間進(jìn)行笛卡爾積。下面就是一個 Cross Join 的例子:
presto:iteblog> SELECT * FROM (VALUES 1, 2) t("left"), (VALUES 3, 4) u("right");left | right------+-------1 | 32 | 31 | 42 | 4(4 rows)
Inner Join
Inner join 在一定條件下連接兩張表。只有在滿足給定條件時,表中的每一行才會與另一個表中的每一行連接。在 Presto SQL 中,INNER JOIN、JOIN 和帶有 WHERE 子句的分隔表都被視為 Inner join。如果查詢包含帶有 where 子句的逗號分隔表,如下所示,它將被讀取為 Cross Join,并在連接操作后應(yīng)用過濾器,后面會由 Presto 優(yōu)化器重寫為 Inner join 查詢。
presto:iteblog> SELECT * FROM (VALUES 1, 2) t("left"), (VALUES 1, 1, 2) u("right")WHERE t."left" = u."right";left | right------+-------1 | 11 | 12 | 2(3 rows)
Left Outer Join
與 Inner join 一樣,Left Outer Join 將左表中的每一行與右表中的匹配行連接起來。如果左表中的行在右表中沒有找到,那么右表中對應(yīng)的列用空值來填充。在 Presto SQL 中,關(guān)鍵字 OUTER 在 LEFT OUTER JOIN 操作中是可選的。換句話說,LEFT JOIN 和 LEFT OUTER JOIN 的意思是一樣的。
presto:iteblog> SELECT * FROM (VALUES 1, 2) t("left")LEFT OUTER JOIN (VALUES 1, 1) u("right")ON t."left" = u."right";left | right------+-------1 | 11 | 12 | NULL(3 rows)
Right Outer Join
Right Outer Join 將右表中的每一行與左表中的匹配行連接起來。如果右表中的行在左表中沒有找到,那么左表中對應(yīng)的列用空值來填充。在 Presto SQL 中,關(guān)鍵字 OUTER 在 RIGHT OUTER JOIN 操作中是可選的。換句話說,RIGHT JOIN 和 RIGHT OUTER JOIN 的意思是一樣的。
presto:iteblog> SELECT * FROM (VALUES 1, 2) t("left")RIGHT OUTER JOIN (VALUES 1, 2, 3) u("right")ON t."left" = u."right";left | right------+-------1 | 12 | 2NULL | 3(3 rows)
Full Outer Join
Full Outer Join 可以看作是左外連接和右外連接的組合。它將每一側(cè)的每一行與另一側(cè)的匹配行連接起來。如果左表中的行在右表中沒有找到,那么右表中對應(yīng)的列用空值來填充。同樣,如果右表中的行在左表中沒有找到,那么左表中對應(yīng)的列用空值來填充。在 Presto SQL 中,關(guān)鍵字 OUTER 在 FULL OUTER JOIN 操作中是可選的。換句話說,F(xiàn)ULL JOIN 和 FULL OUTER JOIN 的意思是一樣的。
presto:iteblog> SELECT * FROM (VALUES 1, 2) t("left")FULL OUTER JOIN (VALUES 1, 3) u("right")ON t."left" = u."right";left | right------+-------1 | 12 | NULLNULL | 3(3 rows)
除了上面提到的 JOIN 類型之外,還有兩種 JOIN 類型:Semi Join 以及 Anti Join。這兩個 JOIN 一般是 Presto 改寫用戶 SQL 產(chǎn)生的。
Semi Join
在 Presto 內(nèi)部,IN/EXISTS 中帶子查詢就會被翻譯成 Semi Join,Semi Join 有兩種變體:Left Semi Join 和 Right Semi Join。顧名思義,Left Semi Join 計算條件,如果左表中有匹配的行,則返回左表中的行。類似地,Right Semi Join 只返回右邊表中匹配的行。以下使用 IN 謂詞的查詢被 Presto 優(yōu)化器轉(zhuǎn)換成 Semi Join:
presto:iteblog> SELECT o_orderkey,o_custkey FROM ordersWHERE o_orderkey IN (SELECT o_orderkeyFROM ordersWHERE o_orderstatus = 'o' AND o_orderdate = '1996-01-02');o_orderkey | o_custkey------------+-----------454791 | 148313376 | 122402209 | 149312295 | 129469061 | 158877861 | 127843492 | 17855620 | 117904289 | 123747713 | 1(10 rows)
Anti Join
Anti Join 是 Presto 另一種內(nèi)部使用的 JOIN,用于在聯(lián)接條件不匹配時從表中返回行。它與 Semi Join 類似,只返回一個表中的行,但 Join 條件與 Semi Join 相反。例如,可以使用 Anti Join 評估以下 NOT IN 查詢。
presto:iteblog> SELECT o_orderkey,o_custkey FROM ordersWHERE o_orderkey IN (SELECT o_orderkeyFROM ordersWHERE o_orderstatus = 'o' AND o_orderdate = '1996-01-02');o_orderkey | o_custkey------------+-----------58781825 | 100249611692451 | 47926945393222 | 14597253041377 | 37193519746180 | 730093485186 | 65360246238592 | 4709943451713 | 15206043661861 | 62653(9 rows)
盡管 Anti Join 可以被視為一種不同的 JOIN 類型,但在 Presto 內(nèi)部通過否定連接條件將其視為 Semi Join。不僅是 Semi Join,任何 JOIN 操作都可以使用其他 JOIN 組成。例如,通過交互參與 JOIN 的表的位置 ,可以將 left outer join 重寫為 right outer join。
