mysql join 算法_【MySQL】之join算法详解
在阿里巴巴的java開發手冊有這么一條強制規定:超過三個表禁止join,需要join的字段,數據類型保持絕對一致,多表關聯查詢時,要保證被關聯的字段需要有索引。
為什么盡量避免使用join?如果使用join,我們應該怎么用呢?接下來我們就一起聊一聊關于join的幾種算法。
Simple Nested-Loop Join
Simple Nested-Loop Join算法是指讀取驅動表t1中的每行數據,將每行數據傳遞到被驅動表t2上,取出被驅動表t2中滿足條件的行,和t1組成結果集。
在這個算法中,需要對t1進行全表掃描,假設t1表1000行數據,那么需要對t2表進行1000次全表掃描,假設t2表也是1000行數據,那么就需要掃描1000 X 1000=1000000行。
示例圖如下:當t1表5行數據,t2表5行數據時,需要掃描25行數據。
Index Nested-Loop Join
index nested-loop join算法的優化思路是通過驅動表的匹配條件,直接與被驅動表的索引進行匹配,減少了被驅動表的掃描次數。
該算法同樣要對驅動表t1進行全表掃描,但是我們在拿著t1表的數據去被驅動表t2進行匹配時可以利用t2表的索引,如果t1表中1000行數據,t2表中1000行數據,那么一共就需要掃描1000+1000=2000行數據。這個過程就跟我們寫程序時的嵌套查詢類似,并且可以用上被驅動表的索引,所以稱之為“Index Nested-Loop Join”,簡稱 NLJ。
示例如下:當t1表有5行數據,t2表有5行數據時,一共需要掃描5+5=10行數據。
Block Nested-Loop Join
Block Nested-Loop join,基于塊的嵌套循環,簡稱BNL算法,其優化思路主要是減少被驅動表的循壞次數,它會將驅動表的數據緩存起來,把參與查詢的列緩存到join buffer里,然后拿join buffer里的數據批量與內層表的數據在join buffer中進行匹配,滿足join條件的,作為結果集的一部分返回。
可以看到該算法對兩個表都進行了全表掃描,因此掃描的行數是兩個表的行數之和。這種場景下,雖然在掃描行數上和NLJ算法一樣,但是由于BNL算法是在內存中進行判斷,速度上會快很多。
join buffer的大小是由參數join_buffer_size設定,默認256k。如果一次放不下驅動表的所有數據,會分段放,這種情況下會導致被驅動表掃描多次。如果被驅動表是冷數據表,并且多次掃描讀取被驅動表間隔超過1S的話,就會將他放入LRU鏈表的young區域,導致業務數據無法進入熱數據區,減少了bufferpool的命中率,這又是另外一個課題了,暫不過多展開。我們可以通過調大join_buffer_size來提高緩存的數據量,減少對被驅動表的掃描次數。
啟用BNL算法需要在optimizer_switch參數中設置block_nested_loop=on。
Batched Key Access
BNL算法提升了join的性能,但是它在通過輔助索引連接后需要回表,就會消耗大量的隨機I/O,我們知道隨機IO對MySQL的影響是非常大的。因此MySQL5.6引入了Batched Key Access(BKA,批量鍵訪問聯接)算法。
再說BKA算法時不得不提的就是MySQL的Multi-Range Read 優化,MRR的目的主要是減少磁盤的隨機訪問。我們都知道,Innodb索引采用的是B+tree的數據結構,數據保存在主鍵索引中,并且是按照主鍵遞增的順序插入的,但是二級索引的排列順序和主鍵的排列順序一般是不一樣的,它保存的主鍵值也并非按照主鍵順序排列,在回表時就會出現隨機訪問主鍵索引的情況。所以如果可以按照主鍵遞增順序查詢的話,對磁盤的讀比較接近順序讀,這樣就能夠提升讀性能。
MRR優化的思路就是在進行范圍查詢時,在得到主鍵值之后,先按照主鍵的順序進行排序,然后拿著排好序的主鍵ID再去主鍵索引進行查詢,這樣就能體現出順序性的優勢了。因為是多值查詢,所以一般用于range、ref類型的查詢。
再說會BKA算法,當被驅動表上有索引可以利用時,那么就在行提交給被 join 的表之前,先對兩個表的對應列的索引字段進行join,得到主鍵值后,按照主鍵排好序后,利用 MRR 技術,批量訪問表取數據,減少了隨機 IO。但是如果被 join 的表沒用索引的話,那就只能使用BNL算法了。
具體算法如下圖:
開啟BKA和MRR的方式:
set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
MySQL在8.0版本已經實現了hash join,這里暫不做介紹。
小結
如何優化join的速度呢,這里給出如下幾點建議:
盡量避免使用join。
用小表作為驅動表,減少外層循環的次數。
多表關聯查詢時,要保證被關聯的字段要有索引。
適當增大join_buffer_size的值,緩存的數據越多,就越能減少被驅動表掃描的次數。
減少不必要的字段查詢。
需要join的字段,數據類型保持絕對一致。
本文分享自微信公眾號 - MySQL數據庫技術棧(Mysqltechnology)。
如有侵權,請聯系 support@oschina.cn 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。
總結
以上是生活随笔為你收集整理的mysql join 算法_【MySQL】之join算法详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ci框架mysql多条件_CI框架同时连
- 下一篇: python sqlserver api