MySQL--BNL/ICP/MRR/BKA

#======================================================##
MySQL關聯查詢算法:
BNL(Block Nested-Loop)
ICP(Index Condition Pushdown)
MRR(Multi-Range Read)
BKA(Batched Key Access)算法

#======================================================##
BNL(Block Nested-Loop)
場景:
假設TB1和TB2進行關聯查詢,以TB1爲外表循環掃描每行數據到TB2中查找匹配的記錄行,但因爲TB2中沒有可使用的索引,須要掃描整個T2表的數據,所以外層TB1的數據行數決定內層TB2的掃描次數。服務器

優化:
將外層表TB1的數據行進行拆分N個Block,每一個Block中包含M條數據,對TB2進行N次掃描,在掃描TB2數據的每一行時將其與一個Block的數據進行匹配,將原來對TB2表的掃描次數從M*N次下降到N次。oop

重點:
一、內表沒有可利用的索引
二、內表和外表的順序不能對換,如LEFT JOIN操做性能

該算法在MySQL 5.1版本中便已存在。優化

#======================================================##
ICP(Index Condition Pushdown)
場景:
假設表TB1上有索引IDX_C1_C2_C3(C1,C2,C3),對於查詢SELECT * FROM TB1 WHERE C1='XXX' AND C3='XXX'blog

在MySQL 5.6版本之前,因爲缺乏C2的過濾條件,Innodb存儲引擎層只能使用索引IDX_C1_C2_C3按照C1='XXX'條件找出全部知足條件的索引記錄,再根據這些索引記錄去彙集索引中查找,將找到的表數據返回給MySQL Server層,而後由MySQL Server層使用C3='XXX'條件進行過濾獲得最終結果。排序


再MySQL 5.6版本中引入ICP特性,Innodb存儲引擎層只能使用索引IDX_C1_C2_C3按照C1='XXX'條件去掃描全部知足條件的索引記錄,再將這些索引記錄按照C3='XXX'條件進行過濾,並按照過濾後的索引記錄去去彙集索引中查找,將找到的表數據返回給MySQL Server層,獲得最終結果。索引

假設知足C1='XXX'條件的數據行爲100000條,而知足C1='XXX' AND C3='XXX'的數據行爲100條,則:
一、在MySQL 5.5版本中,須要對TB1的彙集索引進行100000次Index Seek操做,Innodb存儲引擎層向MySQL Server層傳遞100000行數據。
二、在MySQL 5.6版本中,使用ICP僅須要對TB1的彙集索引進行100次的Index Seek操做,Innodb存儲引擎層向MySQL Server層傳遞100行數據。it

ICP經過將過濾條件由MySQL Server層"下沉"到存儲引擎層,從而達到:
一、減小對彙集索引查找的操做次數;
二、減小從存儲引擎層返回給MySQL Server層的數據量;
三、減小MySQL Server層訪問存儲引擎層的次數。io

PS1: ICP僅使用於非彙集索引。
PS2: 在MySQL 5.6中僅支持普通表進行ICP操做,而MySQL 5.7中支持對分區表進行ICP操做。
#======================================================##
MRR(Multi-Range Read)
假設表TB1上有索引IDX_C1(C1),對於查詢SELECT * FROM TB1 WHERE C1 IN('XXX1','XXX2',....,'XXXN')

在MySQL 5.6版本之前,先按照C1='XXX1'條件對IDX_C1進行索引查找,再按照找到的索引記錄去TB1的彙集索引中找到對應數據記錄,再按照C1='XXX2'...到C1='XXXN'進行操做,將每次操做的結果集合並獲得最終結果集。因爲根據C1條件獲得的索引記錄中的包含的彙集鍵數據時無序的,致使對彙集索引的Index seek操做形成較多的隨機IO,影響服務器存儲性能。

在MySQL 5.6版本中引入MRR特性,先按照C1='XXX1'....和C1='XXXM'的條件找到知足條件的索引記錄放到buffer中,當Buffer滿時再將buffer中的索引記錄按照彙集鍵進行排序,按照排序後的結果去彙集索引中找到相應記錄,經過排序,能夠有效地將原來的隨機查找改成順序查找,將部分隨機IO轉換爲順序IO,提示查詢性能,下降查詢對服務器IO性能的消耗。

PS1: MRR也僅適用於非彙集索引,且根據非彙集索引獲得的結果集在彙集鍵上是隨機無序的。
PS2: 假設上面TB1的彙集索引爲ID,那麼IDX_C1(C1)等價於IDX_C1(C1,ID),若是僅對非彙集索引進行單個等值查詢,那麼獲得的結果集對彙集鍵也是有序的,無需使用MRR特性。
PS3: MRR中涉及到的Buffer的大小取決於參數read_rnd_buffer_size的設置

#======================================================##
BKA(Batched Key Access)
場景:
假設TB1和TB2進行關聯查詢,以TB1爲外表循環到TB2中進行關聯匹配,表TB2上有可以使用的索引。

在MySQL 5.6版本前,只能循環TB1中的數據依次到TB2上進行索引查找,若是TB1上的數據是無序的,則對TB2的索引查找也是隨機的,產生大量的隨機IO操做。
在MySQL 5.6版本中,按照MRR的特性,先將TB1中的數據放入Buffer中,當Buffer滿時對Buffer中的數據按照關聯鍵進行排序,而後有序地對TB2進行索引查找,將部分隨機IO操做轉換爲順序IO操做。

PS1: BKA以來於MRR,所以要使用BKA必須開啓MRR特性,但又因爲基於mrr_cost_based的成本估算不能保證MRR被使用,所以官方推薦關閉mrr_cost_based。
PS2: BKA使用的Buffer的大小取決於參數join buffer size

#======================================================##
設置開啓MRR和BKA並關閉mrr_cost_based
SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';

#======================================================##
BKA和BNL的區別:
一、內表索引,BKA要求內表有可使用的索引,而BNL則是由於內表沒有可以使用的索引而不得已的優化
二、算法目的,BKA算法的目的是減小對內表的隨機Index Seek操做和下降隨機IO,而BNL算法的目的是減小對內表的掃描次數和減小掃描帶來的IO開銷。

#======================================================##

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息