學習Mysql的join算法:Index Nested-Loop Join和Block Nested-Loop Join

閱讀這篇文章,你將會了解
1.什麼是Nested-Loop Join?
2.Index Nested-Loop Join怎麼優化連接?
3.Block Nested-Loop Join怎麼優化連接?

一.Nested-Loop Join

在Mysql中,使用Nested-Loop Join的算法思想去優化join,Nested-Loop Join翻譯成中文則是“嵌套循環連接”。

舉個例子:
select * from t1 inner join t2 on t1.id=t2.tid
(1)t1稱爲外層表,也可稱爲驅動表。
(2)t2稱爲內層表,也可稱爲被驅動表。

//僞代碼表示:
List<Row> result = new ArrayList<>();
for(Row r1 in List<Row> t1){
	for(Row r2 in List<Row> t2){
		if(r1.id = r2.tid){
			result.add(r1.join(r2));
		}
	}
}

在Mysql的實現中,Nested-Loop Join有3種實現的算法:

  • Simple Nested-Loop Join:SNLJ,簡單嵌套循環連接
  • Index Nested-Loop Join:INLJ,索引嵌套循環連接
  • Block Nested-Loop Join:BNLJ,緩存塊嵌套循環連接

在選擇Join算法時,會有優先級,理論上會優先判斷能否使用INLJ、BNLJ:
Index Nested-LoopJoin > Block Nested-Loop Join > Simple Nested-Loop Join

二.Simple Nested-Loop

  1. 簡單嵌套循環連接實際上就是簡單粗暴的嵌套循環,如果table1有1萬條數據,table2有1萬條數據,那麼數據比較的次數=1萬 * 1萬 =1億次,這種查詢效率會非常慢。
  2. 所以Mysql繼續優化,然後衍生出Index Nested-LoopJoin、Block Nested-Loop Join兩種NLJ算法。在執行join查詢時mysql會根據情況選擇兩種之一進行join查詢。

三.Index Nested-LoopJoin(減少內層表數據的匹配次數)

  1. 索引嵌套循環連接是基於索引進行連接的算法,索引是基於內層表的,通過外層表匹配條件直接與內層表索引進行匹配,避免和內層表的每條記錄進行比較, 從而利用索引的查詢減少了對內層表的匹配次數,優勢極大的提升了 join的性能:

原來的匹配次數 = 外層錶行數 * 內層錶行數
優化後的匹配次數= 外層表的行數 * 內層表索引的高度

  1. 使用場景:只有內層表join的列有索引時,才能用到Index Nested-LoopJoin進行連接。
  2. 由於用到索引,如果索引是輔助索引而且返回的數據還包括內層表的其他數據,則會回內層表查詢數據,多了一些IO操作。

四.Block Nested-Loop Join(減少外層表數據的循環次數)

  1. 緩存塊嵌套循環連接通過一次性緩存多條數據,把參與查詢的列緩存到Join Buffer 裏,然後拿join buffer裏的數據批量與內層表的數據進行匹配,從而減少了外層循環的次數。
  2. 當不使用Index Nested-Loop Join的時候,默認使用Block Nested-Loop Join。
  3. 什麼是Join Buffer?
    (1)Join Buffer會緩存所有參與查詢的列而不是隻有Join的列。
    (2)可以通過調整join_buffer_size緩存大小
    (3)join_buffer_size的默認值是256K,join_buffer_size的最大值在MySQL 5.1.22版本前是4G-1,而之後的版本才能在64位操作系統下申請大於4G的Join Buffer空間。
    (4)使用Block Nested-Loop Join算法需要開啓優化器管理配置的optimizer_switch的設置block_nested_loop爲on,默認爲開啓。

五.如何優化Join速度

  1. 用小結果集驅動大結果集,減少外層循環的數據量:
    如果小結果集和大結果集連接的列都是索引列,mysql在內連接時也會選擇用小結果集驅動大結果集,因爲索引查詢的成本是比較固定的,這時候外層的循環越少,join的速度便越快。
  2. 爲匹配的條件增加索引:爭取使用INLJ,減少內層表的循環次數
  3. 增大join buffer size的大小:當使用BNLJ時,一次緩存的數據越多,那麼外層表循環的次數就越少
  4. 減少不必要的字段查詢:
    (1)當用到BNLJ時,字段越少,join buffer 所緩存的數據就越多,外層表的循環次數就越少;
    (2)當用到INLJ時,如果可以不回表查詢,即利用到覆蓋索引,則可能可以提示速度。(未經驗證,只是一個推論)

六.參考文檔

https://www.wengbi.com/thread_99558_1.html
https://www.cnblogs.com/starhu/p/6418842.html
https://www.cnblogs.com/starhu/p/6418833.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章