Using join buffer (Block Nested Loop)java
msyql的錶鏈接算法算法
NLJ 算法:將驅動表/外部表的結果集做爲循環基礎數據,而後循環從該結果集每次一條獲取數據做爲下一個表的過濾條件查詢數據,而後合併結果。若是有多表join,則將前面的表的結果集做爲循環數據,取到每行再到聯接的下一個表中循環匹配,獲取結果集返回給客戶端。oop
Nested-Loop 的僞算法以下:優化
for each row in t1 matching range { for each row in t2 matching reference key { for each row in t3 { if row satisfies join conditions, send to client } } }
Because the NLJ algorithm passes rows one at a time from outer loops to inner loops, tables processed in the inner loops typically are read many timesspa
由於普通Nested-Loop一次只將一行傳入內層循環, 因此外層循環(的結果集)有多少行, 內存循環便要執行多少次.在內部表的鏈接上有索引的狀況下,其掃描成本爲O(Rn),若沒有索引,則掃描成本爲O(Rn*Sn)。若是內部表S有不少記錄,則SimpleNested-Loops Join會掃描內部表不少次,執行效率很是差。code
BNL 算法:將外層循環的行/結果集存入join buffer, 內層循環的每一行與整個buffer中的記錄作比較,從而減小內層循環的次數。索引
舉例來講,外層循環的結果集是100行,使用NLJ 算法須要掃描內部表100次,若是使用BNL算法,先把對Outer Loop表(外部表)每次讀取的10行記錄放到join buffer,而後在InnerLoop表(內部表)中直接匹配這10行數據,內存循環就能夠一次與這10行進行比較, 這樣只須要比較10次,對內部表的掃描減小了9/10。因此BNL算法就可以顯著減小內層循環表掃描的次數。內存
前面描述的query, 若是使用join buffer, 那麼實際join示意以下:it
for each row in t1 matching range { for each row in t2 matching reference key { store used columns from t1, t2 in join buffer if buffer is full { for each row in t3 { for each t1, t2 combination in join buffer { if row satisfies join conditions, send to client } } empty buffer } } } if buffer is not empty { for each row in t3 { for each t1, t2 combination in join buffer { if row satisfies join conditions, send to client } } }
若是t1, t2參與join的列長度只和爲s, c爲兩者組合數, 那麼t3表被掃描的次數爲 io
(S * C)/join_buffer_size + 1
掃描t3的次數隨着join_buffer_size的增大而減小, 直到join buffer可以容納全部的t1, t2組合, 再增大join buffer size, query 的速度就不會再變快了。
MySQL使用Join Buffer有如下要點:
1. join_buffer_size變量決定buffer大小。
2. 只有在join類型爲all, index, range的時候纔可使用join buffer。
3. 可以被buffer的每個join都會分配一個buffer, 也就是說一個query最終可能會使用多個join buffer。
4. 第一個nonconst table不會分配join buffer, 即使其掃描類型是all或者index。
5. 在join以前就會分配join buffer, 在query執行完畢即釋放。
6. join buffer中只會保存參與join的列, 並不是整個數據行。
如何使用
5.6版本及之後,優化器管理參數optimizer_switch中中的block_nested_loop參數控制着BNL是否被用於優化器。默認條件下是開啓,若果設置爲off,優化器在選擇 join方式的時候會選擇NLJ算法。
==========END==========