五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Subquery? No, it's join!

2023-07-06 17:08 作者:Databend  | 我要投稿

作者:王旭東
Databend 研發(fā)工程師

https://github.com/xudong963

基本介紹

在SQL查詢中,子查詢是一種常用的技術,它允許我們在一個查詢內(nèi)部嵌套另一個查詢,以實現(xiàn)更復雜的數(shù)據(jù)檢索和分析。如何在數(shù)據(jù)庫內(nèi)核中高效的處理子查詢是非常有挑戰(zhàn)的。本文將介紹如何在 Databend 中構建 state-of-art 的子查詢 optimizer。

從寬泛的角度,子查詢分為關聯(lián)和非關聯(lián)子查詢, 細分的種類包含:SCALAR/ANY/ALL/SOME/(NOT)IN/(NOT)EXISTS. 對于每一種子查詢的含義,讀者可以參考:https://www.postgresql.org/docs/current/functions-subquery.html?。盡管子查詢有這么多種,但是在 Databend 中,我們只需要處理 SCALAR/EXISTS/ANY 三種子查詢,因為在 binder 階段,可以做如下 SQL 語義等價轉(zhuǎn)換:

  • "in"?=>??"=any(...)"

  • "i > all()"?=> "not(i <= any(...))"

  • "some"?=> "any"

子查詢幾乎可以出現(xiàn)在 SQL 的任何位置,如 "from/where/select/group by/having/order by", 外加關聯(lián)子查詢的存在,所以處理子查詢變得具有挑戰(zhàn)性,在深入子查詢之前,先介紹一下 Databend 為了高效處理子查詢而引入的非標準 join 類型:single join?和?mark join。

  • single join:?single join 的存在是為了處理 scalar 子查詢,left single join 與 left outer join 類似,但是如果超過一個 join partner 被發(fā)現(xiàn)就會報錯,這點對應 scalar 子查詢只產(chǎn)生一列且最多一行結(jié)果。

  • mark join:?mark join 引入了一個新的屬性:mark, 用來標記 tuple 是否有 join partner. 其值可以是 "TRUE, FALSE, NULL", 可以用來處理 ANY/EXISTS 子查詢

有了這兩種非標準 join, 我們可以保證所有的子查詢在經(jīng)過子查詢 optimizer 后已經(jīng)全部轉(zhuǎn)化為 join, 這為 join reorder 提供了更多的可能,可以大幅降低執(zhí)行代價。

非關聯(lián)子查詢

非關聯(lián)子查詢的處理相對簡單,只需要做簡單的變換即可。下面通過幾個簡單的例子來看一下如何展開非關聯(lián)子查詢:

1. 非關聯(lián) scalar 子查詢 "select number, (select number from numbers(10) as t2 where number > 3 limit 1) from numbers(10) as t1", 直接用 single join即可?

2. 非關聯(lián) exists 子查詢 "select number, exists(select * from numbers(10) as t2 where number > 3) from numbers(10) as t1";, 給子查詢加上 "limit 1,?count(*)"?和 "count(*) = 1?operator", 其中 "limit 1"?可以使查詢更加高效,因為只需要判斷是否存在即可?

3. 非關聯(lián) any 子查詢 "select number from numbers(10) as t1 where number > any(select number from numbers(20) as t2) or number > 1;", 在這條 SQL 中,因為包含 disjunction predicate,所以不能用 semi join 來對轉(zhuǎn)化子查詢,mark join 的 mark 列將替換子查詢 => "marker or number > 1"?

關聯(lián)子查詢

在介紹關聯(lián)子查詢前,需要引入?dependent join, dependent join 會為 LHS 中的每一行執(zhí)行一次 RHS 。

核心思想在于如何消除 dependent join 中的 correlated columns?下面通過一條 ANY 關聯(lián)子查詢來看一下是如何去關聯(lián)的 "select a from t1 where a > any(select b from t2 where t1.a < 1) or a > 1;mysql>?desc?t1;"

子查詢中包含 correlated column "t1.a", 核心的一步就是對子查詢中的表進行擴展(cross join),t2 x t1(a)?, 擴展后的子查詢自然就完成了去關聯(lián)。?

擴展后的表假設叫 t3 包含兩列(b, a'), t3 會與 t1 進行 mark join, 返回 (t1.a, mark) 兩列,mark 列用于 filter: "mark or a > 1"?中,對 mark join 后的結(jié)果進行進一步過濾。

這里需要注意的是 mark join 的 equi condition 和 non-equi condition.至此,子查詢處理的核心思想已經(jīng)介紹完了。還有很多工程上的優(yōu)化和特殊情況就不展開講述了,比如

  1. 如何正確的處理 NULL, 特別是在 mark join 的實現(xiàn)中,NULL 的正確處理對子查詢結(jié)果的正確性非常重要

  2. 在對子查詢中的表進行拓展時,直接 cross join 有一定的開銷,能否避免 cross join?

  3. mark join 在什么情況下可以轉(zhuǎn)化為 semi join?

  4. ......

縱觀全文,所有的子查詢最終的形態(tài)都是 join, 所以 join 的性能很大程度上決定了子查詢的性能,下一篇我們講一講 Databend join 從 0 到 1 的一個迭代過程。

Subquery? No, it's join!的評論 (共 條)

分享到微博請遵守國家法律
镇江市| 疏勒县| 罗江县| 麻栗坡县| 山西省| 陆河县| 顺义区| 彭州市| 翼城县| 轮台县| 沙洋县| 唐海县| 百色市| 离岛区| 巨鹿县| 南丹县| 吉首市| 通江县| 长治县| 白银市| 大关县| 辛集市| 京山县| 抚远县| 任丘市| 宜阳县| 武平县| 翁牛特旗| 田阳县| 张家港市| 曲水县| 威信县| 白玉县| 萨嘎县| 梅河口市| 邛崃市| 高雄市| 施秉县| 错那县| 都江堰市| 涿州市|