MySQL 8.0 新特性-antijoin

2020-12-11 偏執的IT工匠

MySQL 8.0.17版本引入了一個antijoin的優化,這個優化能夠將where條件中的not in(subquery), not exists(subquery),in(subquery) is not true,exists(subquery) is not true,在內部轉化成一個antijoin(反連接),以便移除裡面的子查詢subquery,這個優化在某些場景下,能夠將性能提升20%左右。

原文地址:mytecdb.com/blogDetail.php?id=108

1. antijoin使用場景

antijoin使用的場景案例通常如下:

找出在集合A且不在集合B中的數據找出在當前季度裡沒有購買商品的客戶找出今年沒有通過考試的學生找出過去3年,某個醫生的病人中沒有進行醫學檢查的部分上面這些場景,以第4個為例,轉換成一個SQL,通常如下:

如果SQL按照這種形式去寫,通常沒有太多的優化空間。我們需要從patients表讀取每條記錄,對於每條記錄,帶到子查詢中,檢查是否滿足條件。因為子查詢的where子句依賴patients.patient_id,patients 表的每一條記錄遍歷,都會導致子查詢被重複執行,嚴重影響性能。

優化這種SQL的第一步就是打破上層查詢與子查詢之間的邊界,將後者也就是子查詢合併到上層查詢裡面。

看一下優化之後的SQL,如下:

優化後的SQL使用了antijoin關鍵字,它和join操作類似,join通常尋找滿足匹配條件的記錄,而antijoin尋找不匹配的記錄。更準確地說,它從左邊表選擇記錄,然後檢查右邊表,根據on條件,檢查是否沒有記錄能夠匹配上,如果沒有記錄匹配,那麼左邊的這條記錄就可以作為結果返回。

2. antijoin內部優化策略

MySQL有兩種策略用於執行antijoin。

First MatchMaterialization2.1 First Match策略

First Match 策略,從patients表中讀取一條記錄,然後在exams表中尋找匹配,如果沒有匹配上,則將這條記錄作為結果返回。這種方式與使用子查詢並沒有太大的區別。

2.2 Materialization策略

Materialization策略,對於上述SQL例子,ON子句有3個子條件,分別是

exams.type='check-up'exams.date>=date_sub(now(), interval 3 year)patients.patient_id=exams.patient_id3個條件中只有一個依賴patients表,所以MySQL可以創建一個臨時表tmp,這個臨時表由exams表按照前兩個條件過濾後的數據組成,就像下面這樣:

MySQL優化器會自動在tmp的patient_id欄位上添加索引,然後從patients表讀取記錄,使用索引匹配tmp表中的記錄,如果沒有匹配上,則返回這條記錄。

相對於First Match策略,Materialization策略主要有以下優勢:

exams表只讀取一次,用於創建tmp表。tmp表相對於exams表,有更少的記錄,訪問tmp表要比exams表更快。tmp表上由於創建了索引,訪問起來更快,而原始表exams很可能沒有索引。當然,這種策略創建臨時表,也有一些前期的成本消耗,比如需要申請內存來存儲臨時表數據,比如臨時表非常大,需要將臨時表存儲在磁碟上。因此兩種策略哪一種更好,依賴於具體的場景。幸運的是,MySQL有一個基於成本的優化器,通過計算兩種策略基於數據行數的成本,條件的選擇性,索引的使用,最終選擇成本最低的那個策略。

3. 總結

antijoin優化適用於not exists(subquery), not in(subquery)這類查詢,在某些場景下,能夠對這類SQL進行很好的優化和性能提高。antijoin有兩種執行策略,First Match和Materialization,優化器根據成本模型進行選擇。

相關焦點

  • MySQL 8.0 新特性:哈希連接(Hash Join)
    https://dev.mysql.com/doc/refman/8.0/en/hash-joins.htmlMySQL 實現了用於內連接查詢的 hash join 方式。例如,從 MySQL 8.0.18 開始以下查詢可以使用 hash join 進行連接查詢:SELECT *     FROM t1     JOIN t2         ON t1.c1=t2.c1;Hash join 不需要索引的支持。
  • MySQL中left join的幾個SQL對比
    > select *from test1;+----+-+| id | name |+----+-+| 1 | aa || 2 | bb || 3 | cc || 4 | bb || 5 | bb |+----+-+5 rows in set (0.00 sec)mysql> select *from test2;+----+-+| id |
  • 新特性解讀 | MySQL 8.0 窗口函數框架用法
    之前在 MySQL 8.0 新特性欄目裡介紹過 8.0 的窗口函數的用法,沒有細化到全部的語法,恰巧今天有客戶追問其中的框架子句用法,寫出來大家一起探討。窗口函數其實就是一個分組窗口內部處理每條記錄的函數,這個窗口也就是之前聚合操作的窗口。
  • MySQL 8.0.23新特性 - 不可見列
    /https://lefred.be/content/mysql-invisible-column-part-ii/https://lefred.be/content/mysql-invisible-column-part-iii/在新的MySQL 8.0.23中,引入了新的有趣功能:不可見列。
  • MySQL 8.0 正式版 8.0.11 發布:比 MySQL 5.7 快 2 倍
    下面簡要介紹 MySQL 8 中值得關注的新特性和改進。1. 性能:MySQL 8.0 的速度要比 MySQL 5.7 快 2 倍。MySQL 8.0 在以下方面帶來了更好的性能:讀/寫工作負載、IO 密集型工作負載、以及高競爭("hot spot"熱點競爭問題)工作負載。
  • Mysql 8 重要新特性 - CTE 通用表表達式
    前言Mysql 8 正式發布了,新增了很多優秀特性,之後我會挑些重點來分享。
  • MySQL 8.0.16穩定版發布 目前不支持between和and
    MySQL 8.0.16 穩定版(GA)已於上個月發布,距推出 8.0.15 僅過去了兩個月。繼續看看 MySQL 8.0.16 有哪些新特性。   帳號管理   具有 DROP ROLE 權限的用戶只能刪除被鎖定的帳戶,而不能刪除未鎖定的帳號。
  • MySQL 8.0.18 穩定版發布,Hash Join 如期而至
    MySQL 8.0.18 穩定版(GA)已於昨日正式發布,Hash Join 也如期而至。
  • MySQL:LEFT JOIN 避坑指南
    在我們使用mysql查詢的過程中可謂非常常見,比如博客裡一篇文章有多少條評論、商城裡一個貨物有多少評論、一條評論有多少個贊等等。~~~~~~~~~~~~~~~~答案是兩個需求都是第一條語句是正確的,要搞清楚這個問題,就得明白mysql對於left join的執行原理,下節進行展開。
  • MySql 之 left join 避坑指南
    在我們使用mysql查詢的過程中可謂非常常見,比如博客裡一篇文章有多少條評論、商城裡一個貨物有多少評論、一條評論有多少個贊等等。答案是兩個需求都是第一條語句是正確的,要搞清楚這個問題,就得明白mysql對於left join的執行原理,下節進行展開。
  • 我想說:mysql的join 真的很弱
    此時說明mysql查詢有些吃力了,但是仍然嫩查詢出來。 步驟5.1,mysql查詢不出來,4表連接,對我本機mysql來說,1.5億數據超過極限了(我調優過這個SQL,執行計劃和索引都走了,沒有問題,show profile顯示在sending data.這個問題另外文章詳談。)
  • MySQL:Left Join 避坑指南
    在我們使用mysql查詢的過程中可謂非常常見,比如博客裡一篇文章有多少條評論、商城裡一個貨物有多少評論、一條評論有多少個贊等等。答案是兩個需求都是第一條語句是正確的,要搞清楚這個問題,就得明白mysql對於left join的執行原理,下節進行展開。
  • Mysql - JOIN詳解
    如果之前對不同JOIN的執行結果沒有概念,可以結合這篇文章往下看2 JOIN的執行順序以下是JOIN查詢的通用結構SELECT <row_list> FROM <left_table> <inner|left|right> JOIN <right_table> ON <join
  • MySQL:left join 避坑指南
    現象left join在我們使用mysql查詢的過程中可謂非常常見,比如博客裡一篇文章有多少條評論、商城裡一個貨物有多少評論、一條評論有多少個贊等等。但是由於對join、on、where等關鍵字的不熟悉,有時候會導致查詢結果與預期不符,所以今天我就來總結一下,一起避坑。
  • MySQL - JOIN 詳解
    2 JOIN的執行順序以下是JOIN查詢的通用結構:SELECT <row_list>  FROM <left_table>    <inner|left|right> JOIN <right_table>      ON <join
  • SQL-JOIN全解析
    例如下面這張用爛了的圖,可以幫你快速理解每個join用法的效果:這張圖描述了left join(左連接)、right join(右連接) 、inner join(內連接)、outer join(外連接)相關的7種用法。
  • 超詳細mysql left join,right join,inner join用法分析
    比較詳細的mysql的幾種連接功能分析下面是例子分析表A記錄如下: aID        aNum
  • mysql 矩陣類型專題及常見問題 - CSDN
    特性bytes極大整數值FLOAT4 bytes單精度 浮點數值DOUBLE8 bytes雙精度 浮點數值DECIMAL對DECIMAL(M,D) ,如果M>D,為M+2否則為D+2小數值字符串類型0-255 bytes定長字符串VARCHAR0-65535 bytes變長字符串TINYBLOB0-255 bytes不超過 255 個字符的二進位字符串TINYTEXT0-255 bytes短文本字符串
  • mysql 如何優化left join
    and c.hotel_id =h.hotel_id where h.hotel_id is null    這個sql是用來查詢出c表中有h表中無的記錄,所以想到了用left join的特性(返回左邊全部記錄,右表不滿足匹配條件的記錄對應行返回null)來滿足需求,不料這個查詢非常慢。
  • PHP7.0 的新特性
    PHP7.0 的新特性經常會被面試官問到,在平時的項目開發中運用它們也會提升一定的代碼質量和代碼運行性能,可見這個知識點的重要性。不過有很多人都沒有去系統的了解掌握,今天我剛好系統整理了一番分享出來。$b:0;PHP7+:$c = $b??