轉載自:https://zhuanlan.zhihu.com/p/54275505mysql
瞭解join 算法原理以前你可能還須要瞭解:算法
mysql索引原理:勤勞的小手:平衡二叉樹、B樹、B+樹、B*樹 理解其中一種你就都明白了sql
Simple Nested-Loop Join(簡單的嵌套循環鏈接)
簡單來講嵌套循環鏈接算法就是一個雙層for 循環 ,經過循環外層表的行數據,逐個與內層表的全部行數據進行比較來獲取結果,當執行select * from user tb1 left join level tb2 on tb1.id=tb2.user_id緩存
時,咱們會按相似下面代碼的思路進行數據匹配:oop
整個匹配過程會以下圖:性能
特色:mysql索引
Nested-Loop Join 簡單粗暴容易理解,就是經過雙層循環比較數據來得到結果,可是這種算法顯然太過於粗魯,若是每一個表有1萬條數據,那麼對數據比較的次數=1萬 * 1萬 =1億次,很顯然這種查詢效率會很是慢。優化
固然mysql 確定不會這麼粗暴的去進行表的鏈接,因此就出現了後面的兩種對Nested-Loop Join 優化算法,在執行join 查詢時mysql 會根據狀況選擇 後面的兩種優join優化算法的一種進行join查詢。spa
Index Nested-Loop Join(索引嵌套循環鏈接)
Index Nested-Loop Join其優化的思路 主要是爲了減小內層表數據的匹配次數, 簡單來講Index Nested-Loop Join 就是經過外層表匹配條件 直接與內層表索引進行匹配,避免和內層表的每條記錄去進行比較, 這樣極大的減小了對內層表的匹配次數,從原來的匹配次數=外層錶行數 * 內層錶行數,變成了 外層表的行數 * 內層表索引的高度,極大的提高了 join的性能。3d
案例:
如SQL:select * from user tb1 left join level tb2 on tb1.id=tb2.user_id
當level 表的 user_id 爲索引的時候執行過程會以下圖:
注意:使用Index Nested-Loop Join 算法的前提是匹配的字段必須創建了索引。
Block Nested-Loop Join(緩存塊嵌套循環鏈接)
Block Nested-Loop Join 其優化思路是減小外層表的循環次數,Block Nested-Loop Join 經過一次性緩存多條數據,把參與查詢的列緩存到join buffer 裏,,而後拿join buffer裏的數據批量與內層表的數據進行匹配,從而減小了外層循環的次數,當咱們不使用Index Nested-Loop Join的時候,默認使用的是Block Nested-Loop Join。
案例:
如SQL:select * from user tb1 left join level tb2 on tb1.id=tb2.user_id
當level 表的 user_id 不爲索引的時候執行過程會以下圖:
注意:
一、使用Block Nested-Loop Join 算法須要開啓優化器管理配置的optimizer_switch的設置block_nested_loop爲on 默認爲開啓,若是關閉則使用Simple Nested-Loop Join 算法;
經過指令:Show variables like 'optimizer_switc%'; 查看配置
二、設置join buffer 的大小
經過join_buffer_size參數可設置join buffer的大小
指令:Show variables like 'join_buffer_size%';
Join 算法總結
不管是Index Nested-Loop Join 仍是 Block Nested-Loop Join 都是在Simple Nested-Loop Join
的算法的基礎上 減小嵌套的循環次數, 不一樣的是 Index Nested-Loop Join 是經過索引的機制減小內層表的循環次數,Block Nested-Loop Join 是經過一次緩存多條數據批量匹配的方式來減小外層表的循環次數,經過 理解join 的算法原理咱們能夠得出如下表鏈接查詢的優化思路。
一、永遠用小結果集驅動大結果集(其本質就是減小外層循環的數據數量)
二、爲匹配的條件增長索引(減小內層表的循環次數)
三、增大join buffer size的大小(一次緩存的數據越多,那麼外層表循環的次數就越少)
四、減小沒必要要的字段查詢(字段越少,join buffer 所緩存的數據就越多,外層表的循環次數就越少)