背景
在通常情況下,當遇到包含any/all子查詢的語句時,往往需要遵循嵌套執行的方式,因此其查詢效率較低。Oceanbase中制定了相應的any/all子查詢優化規則,能夠能夠識別并優化符合條件的any/all子查詢,從而有效提升查詢的性能。
any/all子查詢優化規則的基本原理
any/all子查詢優化規則主要包含對以下兩種情況的處理:
- min/max改寫:當any/all子查詢的表達式類型為比較運算符時,將子查詢改寫為min/max聚合子查詢。
- any/all消除:當any/all子查詢的內容為單個表達式時,將any/all子查詢轉換為普通子查詢,在simplify規則執行時會消除該子查詢。
min/max改寫
考慮如下情況:
SELECT * FROM t1 WHERE c1 > ALL(SELECT c1 FROM t2)
上述例子在默認情況下,需要按照嵌套的方式執行,即對父查詢中的每一條記錄,都需要判斷是否滿足子查詢中的條件。結合該語句的語義,可以將子查詢條件進行如下改寫:
SELECT * FROM t1 WHERE c1 > ALL(SELECT max(c1) FROM t2)
經過改寫后,子查詢被轉換成了聚合子查詢。在實際執行時,可以將子查詢先行聚合,然后將得到的結果用于父查詢的過濾,從而大大提升了查詢效率。
any/all消除
考慮如下情況:
SELECT * FROM t1 WHERE c1 > ALL(SELECT 100)
上述例子中的子查詢為單表達式,可以移除any/all,如下所示:
SELECT * FROM t1 WHERE c1 > (SELECT 100)
在simpify規則執行時,會進一步消除子查詢。
代碼解析
any/all子查詢優化規則的入口為ObTransformSubqueryCoalesce::transform_one_stmt,該函數最終調用do_transform_any_all函數進行優化,執行流程如下:
- 調用transform_any_all_as_min_max函數對any/all子查詢語句進行min/max改寫。
- 調用eliminate_any_all_before_subquery函數將單表達式的any/all子查詢轉化為普通子查詢。
transform_any_all_as_min_max函數負責將any/all子查詢改寫為聚合子查詢,能夠被改寫的子查詢需要滿足如下條件:
- 子查詢對應的表達式必須為>,>=,<,<=中的一種。
- 子查詢必須只包含一個select列,且該列需要屬于某個索引前綴。
- 如果子查詢為all類型,則select列必須為非空列。
該函數最終調用do_transform_any_all_as_min_max函數進行改寫,該函數主要將select列替換成對應列的min/max表達式,對于all類型的子查詢,需要額外添加having非空條件,如下所示:
having max/min(col) is not null
eliminate_any_all_before_subquery函數負責將單表達式的any/all子查詢轉換為普通子查詢,該函數執行邏輯較為簡單,這里不再贅述。
OceanBase 云數據庫現已支持免費試用,現在申請,體驗分布式數據庫帶來全新體驗吧 ~