《DBNotes:Join算法的前世今生》

目錄

  • NestLoopJoin算法
    • Simple Nested-Loop Join
    • Index Nested-Loop Join
    • Block Nested-Loop Join
    • Batched Key Access
  • Hash Join算法
    • In-Memory Join(CHJ)
    • On-Disk Hash Join
  • 參考鏈接

在8.0.18之前,MySQL只支持NestLoopJoin算法,最簡單的就是Simple NestLoop Join,MySQL針對這個算法做了若干優化,實現了Block NestLoop Join,Index NestLoop Join和Batched Key Access等,有了這些優化,在一定程度上能緩解對HashJoin的迫切程度。但是HashJoin的支持使得MySQL優化器有更多選擇,SQL的執行路徑也能做到更優,尤其是對于等值join的場景。

NestLoopJoin算法

長期以來,在MySQL中執行聯接的唯一算法是嵌套循環算法的變體。

Simple Nested-Loop Join

如果我們執行這樣一條等值查詢語句:

select * from t1 straight_join t2 on (t1.a=t2.b);

由于表 t2 的字段 b 上沒有索引,每次到 t2 去匹配的時候,就要做一次全表掃描。就相當于是雙for循環。如果 t1 和 t2 都是 10 萬行的表(當然了,這也還是屬于小表的范圍),就要掃描 100 億行。
SimpleNestLoopJoin顯然是很低效的,對內表需要進行N次全表掃描,實際復雜度是N*M,N是外表的記錄數目,M是記錄數,代表一次掃描內表的代價。為此,MySQL針對SimpleNestLoopJoin做了若干優化。

Index Nested-Loop Join

如果我們能對內表的join條件建立索引,那么對于外表的每條記錄,無需再進行全表掃描內表,只需要一次Btree-Lookup即可,整體時間復雜度降低為N*O(logM)。
再來看看這一句

select * from t1 straight_join t2 on (t1.a=t2.a);

在這條語句里,被驅動表 t2 的字段 a 上有索引,join 過程用上了這個索引,因此這個語句的執行流程是這樣的:
在這里插入圖片描述
執行流程示意圖如下:
在這里插入圖片描述
在這里插入圖片描述
對比HashJoin,對于外表每條記錄,HashJoin是一次HashTable的search,當然HashTable也有build時間,還需要處理內存不足的情況,不一定比INLJ好。

Block Nested-Loop Join

MySQL采用了批量技術,即一次利用join_buffer_size緩存足夠多的記錄,每次遍歷內表時,每條內表記錄與這一批數據進行條件判斷,這樣就減少了掃描內表的次數,如果內表比較大,間接就緩解了IO的讀壓力。
Simple Nested-Loop Join 與 Block Nested-Loop Join從時間復雜度上來說,這兩個算法是一樣的。但是,Block Nested-Loop Join是內存操作,速度上會快很多,性能也更好。
示意圖如下:
在這里插入圖片描述

Batched Key Access

IndexNestLoopJoin利用join條件的索引,通過Btree-Lookup去匹配減少了遍歷內表的代價。如果join條件是非主鍵列,那么意味著大量的回表和隨機IO。BKA優化的做法是,將滿足條件的一批數據按主鍵排序,這樣回表時,從主鍵的角度來說就相對有序,緩解隨機IO的代價。BKA實際上是利用了MRR特性(MultiRangeRead),訪問數據之前,先將主鍵排序,然后再訪問。主鍵排序的緩存大小通過參數read_rnd_buffer_size控制。

Hash Join算法

NestLoopJoin算法簡單來說,就是雙重循環,遍歷外表(驅動表),對于外表的每一行記錄,然后遍歷內表,然后判斷join條件是否符合,進而確定是否將記錄吐出給上一個執行節點。從算法角度來說,這是一個M*N的復雜度。HashJoin是針對equal-join場景的優化,基本思想是,將外表數據load到內存,并建立hash表,這樣只需要遍歷一遍內表,就可以完成join操作,輸出匹配的記錄。如果數據能全部load到內存當然好,邏輯也簡單,一般稱這種join為CHJ(Classic Hash Join),之前MariaDB就已經實現了這種HashJoin算法。如果數據不能全部load到內存,就需要分批load進內存,然后分批join,下面具體介紹這幾種join算法的實現。

In-Memory Join(CHJ)

HashJoin一般包括兩個過程,創建hash表的build過程和探測hash表的probe過程。
1).build phase
遍歷外表,以join條件為key,查詢需要的列作為value創建hash表。這里涉及到一個選擇外表的依據,主要是評估參與join的兩個表(結果集)的大小來判斷,誰小就選擇誰,這樣有限的內存更容易放下hash表。
2).probe phase
hash表build完成后,然后逐行遍歷內表,對于內表的每個記錄,對join條件計算hash值,并在hash表中查找,如果匹配,則輸出,否則跳過。所有內表記錄遍歷完,則整個過程就結束了
在這里插入圖片描述

On-Disk Hash Join

CHJ的限制條件在于,要求內存能裝下整個外表。在MySQL中,Join可以使用的內存通過參數join_buffer_size控制。如果join需要的內存超出了join_buffer_size,那么CHJ將無能為力,只能對外表分成若干段,每個分段逐一進行build過程,然后遍歷內表對每個分段再進行一次probe過程。假設外表分成了N片,那么將掃描內表N次。這種方式當然是比較弱的。

在MySQL8.0中,如果join需要內存超過了join_buffer_size,build階段會首先利用hash算將外表進行分區,并產生臨時分片寫到磁盤上;然后在probe階段,對于內表使用同樣的hash算法進行分區。由于使用分片hash函數相同,那么key相同(join條件相同)必然在同一個分片編號中。接下來,再對外表和內表中相同分片編號的數據進行CHJ的過程,所有分片的CHJ做完,整個join過程就結束了。這種算法的代價是,對外表和內表分別進行了兩次讀IO,一次寫IO。相對于之之前需要N次掃描內表IO,現在的處理方式更好。
順序為:外表的分片、內表分片、哈希連接
在這里插入圖片描述

參考鏈接

join語句怎么優化?
MySQL8.0 新特性 Hash Join
哈希加入MySQL 8
MySQL · 新特征 · MySQL 哈希連接實現介紹

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/377065.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377065.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377065.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何解決迅雷插件導致IE10崩潰的問題

Windows 8里面帶的IE10酷不酷?沉浸式界面果然不同凡響,IE10讓人幾乎認不出來了!這是微軟的瀏覽器么?上面這張圖是Windows8下Metro UI的新界面IE10,不過當我們切換回傳統桌面的時候,也有IE10的經典版的。好吧…

UNITY3D與iOS交互解決方案

原地址:http://bbs.18183.com/thread-456979-1-1.html 本帖最后由 啊,將進酒 于 2014-2-27 11:17 編輯 “授人以魚,不如授人以漁”,以UNITY3D調用iOS版的91SDK為例,利用C# / C / OBJ-C交互原理,本文將詳細介紹UNITY3D與iOS之間交互…

c:if equal_C ++中的std :: equal()

c:if equalequal()作為STL函數 (equal() as a STL function) Syntax: 句法: bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2);Where, 哪里, InputIterator1 first iterator to start of the first sequence range I…

《DBNotes:Buffer Pool刷臟頁細節以及改進》

本筆記知識沿用之前DBNotes: Buffer Pool對于緩沖頁的鏈表式管理的部分知識 目錄獲取一個空閑頁的源碼邏輯Page_Cleaner_ThreadLRU_Manager_ThreadHazard Pointer作為驅逐算法改進參考獲取一個空閑頁的源碼邏輯 任何一個讀寫請求都需要從Buffer pool來獲取所需頁面。如果需要的…

WordPress刪除數據中標題重復文章的方法

一種是刪除重復的方法是:使用插件,大家可以去官網上下載 二種刪除重復的方法是:登錄數據庫,使用sql語句刪除,具體的語句為如下代碼: CREATE TABLE my_tmp AS SELECT MIN(ID) AS col1 FROM wp_posts GROUP BY post_titl…

hibernate配置

hibernate.cfg.xml <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd&quo…

html中表單元素_HTML中的表單元素

html中表單元素1)<input>元素 (1) The <input> Element) The <input> element is used to get input from the user in an HTML form. <input>元素用于以HTML形式從用戶獲取輸入。 <input> tag is used to get input using input element, the …

《搜索算法——DFS、BFS、回溯》

目錄深搜200. 島嶼數量695. 島嶼的最大面積130. 被圍繞的區域547. 省份數量417. 太平洋大西洋水流問題回溯廣搜111. 二叉樹的最小深度752. 打開轉盤鎖深搜與廣搜結合934. 最短的橋深搜 深搜DFS&#xff0c;在搜索到一個新節點時&#xff0c;立即對該新節點進行遍歷&#xff0c…

AP in R

AP聚類算法是目前十分火的一種聚類算法&#xff0c;它解決了傳統的聚類算法的很多問題。不僅簡單&#xff0c;而且聚類效果還不錯。這里&#xff0c;把前兩天學習的AP算法在R語言上面的模擬&#xff0c;將個人筆記拿出來與大家分享一下&#xff0c;不談AP算法的原理&#xff0c…

nginx 模塊解析

nginx的模塊非常之多&#xff0c;可以認為所有代碼都是以模塊的形式組織&#xff0c;這包括核心模塊和功能模塊&#xff0c;針對不同的應用場合&#xff0c;并非所有的功能模塊都要被用到&#xff0c;附錄A給出的是默認configure&#xff08;即簡單的http服務器應用&#xff09…

python關鍵字和保留字_Python關鍵字

python關鍵字和保留字關鍵詞 (Keywords) Keywords are the reserved words in Python programming language (and, any other programming languages like C, C, Java, etc) whose meanings are defined and we cannot change their meanings. In python programming languages…

《LeetcodeHot100非困難題補錄》

最近比較閑&#xff0c;也比較焦慮&#xff0c;刷刷題吧 目錄11. 盛最多水的容器22. 括號生成31. 下一個排列48. 旋轉圖像49. 字母異位詞分組56. 合并區間75. 顏色分類79. 單詞搜索114. 二叉樹展開為鏈表141. 環形鏈表148. 排序鏈表152. 乘積最大子數組169. 多數元素207. 課程表…

Java里String.split需要注意的用法

我們常常用String的split()方法去分割字符串&#xff0c;有兩個地方值得注意&#xff1a; 1. 當分隔符是句號時(".")&#xff0c;需要轉義&#xff1a; 由于String.split是基于正則表達式來分割字符串&#xff0c;而句號在正則表達式里表示任意字符。 //Wrong: //Str…

C# Socket 例子(控制臺程序)

服務器代碼 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.IO;namespace TCPListener {class Program{static void Main(string[] args){const int BufferSize 1024;Con…

Scala中的值類

Value classes are a special mechanism in Scala that is used to help the compiler to avoid allocating run time objects. 值類是Scala中的一種特殊機制&#xff0c;用于幫助編譯器避免分配運行時對象。 This is done by defining a subclass of AnyVal. The only parame…

《MySQL8.0.22:Lock(鎖)知識總結以及源碼分析》

目錄1、關于鎖的一些零碎知識&#xff0c;需要熟知事務加鎖方式&#xff1a;Innodb事務隔離MVCC多版本并發控制常用語句 與 鎖的關系意向鎖行級鎖2、鎖的內存結構以及一些解釋3、InnoDB的鎖代碼實現鎖系統結構lock_sys_tlock_t 、lock_rec_t 、lock_table_tbitmap鎖的基本模式的…

關于ORA-04021解決辦法(timeout occurred while waiting to lock object)

某個應用正在鎖定該表或者包 表為 select b.SID,b.SERIAL#,c.SQL_TEXT from v$locked_object a, v$session b, v$sqlarea c where a.SESSION_ID b.SID and b.SQL_ADDRESS c.ADDRESS and c.sql_text like %table_name% 包為 select B.SID,b.USERNAME,b.MACHINE FROM V$ACCESS …

HtmlAutoTestFrameWork

前段時間做的自動化測試的是Silverlight的&#xff0c;框架都已經搭好。突然測試發現這里還有一個要發送郵件的html頁面&#xff0c;并且將另外啟動瀏覽器&#xff0c;于是今天下午把這個html的也寫出來。用法 &#xff1a; HtmlAutoTestFrameWork htf new HtmlAutoTestFrameW…

L8ER的完整形式是什么?

L8ER&#xff1a;稍后 (L8ER: Later) L8ER is an abbreviation of "Later". L8ER是“ Later”的縮寫 。 It is an expression, which is commonly used in messaging or chatting on social media networking sites like Facebook, Yahoo Messenger, and Gmail, etc…

Randomize select algorithm 隨機選擇算法

從一個序列里面選擇第k大的數在沒有學習算法導論之前我想最通用的想法是給這個數組排序&#xff0c;然后按照排序結果返回第k大的數值。如果使用排序方法來做的話時間復雜度肯定至少為O&#xff08;nlgn&#xff09;。 問題是從序列中選擇第k大的數完全沒有必要來排序&#xff…