Mysql優化,ICP、BNL算法、BKA算法、MMR算法


ICP(Index Condition Pushdown,索引條件下推)是MySQL5.6版本中的新特性,是一種在存儲引擎層使用索引過濾數據的一種優化方式。

  • 出現原因:ICP出現Mysql5.6以前,Mysql查詢數據是通過索引查詢到主鍵數據,然后再根據數據行回到Mysql Server層做Using where回表查詢檢索,這樣子把查詢回到了Mysql服務層中;Mysql5.6的ICP則是通過將此部分過濾條件直接放到存儲引擎層完成,避免更多的回Mysql服務層做操作,通過存儲引擎層把滿足數據的行讀取出
  • 目的:ICP能減少引擎層訪問基表的次數和MySQL Server訪問存儲引擎的次數,減少IO次數,提高查詢語句性能;減少全行讀取次數;

場景

索引列:user_id_user_name(user_id, user_name)
  • desc select * from user where user_id = 1 and user_name like '%23%';
  • desc select user_id from user where user_id = 1 and user_name like '%23%';
  1. ICP開啟時的執行計划含有Using index condition提示,表示優化器使用了ICP對數據訪問進行優化
  2. ICP關閉時的執行計划顯示Using where; Using index
優點
1. ICP的目標是減少從基表中讀取操作的數量,從而降低IO操作 2. 當使用ICP優化時,執行計划Desc的Extra列顯示Using index condition提示 3. 數據庫配置set optimizer_switch='index_condition_pushdown=on';
局限性
1. Mysql5.6中支持MyISAM、InnoDB 2. ICP只能用於二級索引,不能用於主索引 3. 當SQL使用覆蓋索引時但只檢索部分數據時,ICP 無法使用。例如:select * from可以用到,而select user_id, user_name from 不能使用到ICP。必須查詢整行數據 4. Mysql5.6中不支持分區表的ICP,從MySQL 5.7.3開始支持分區表的ICP 5. ICP的加速效果取決於在存儲引擎內通過ICP篩選掉的數據的比例 5. ICP的優化策略可用於range、ref、eq_ref、ref_or_null 類型的訪問數據方法

BNL(Block Nested-Loop Join)算法。NLJ的原理是內外兩層循環,對外循環中的每條記錄,都要再內循環中做一次檢索。foreacht(){foreacht(){}}

兩種情況會導致NLJ性能降低
1. 外循環的結果集大小 2. 內循環掃描數據的效率(所以增加在on上增加索引即是為了提升效率,這也是為什么on上要加索引的原因)

常見的優化方案是在驅動表(外循環)表上加上盡可能的where條件並創建合適索引,使得外循環的結果集更小,讀取效率更高;內循環為了掃描效率提高,通常需要在關聯字段上加索引

使用條件
1. 只有當join類型是all/index/range時才可以,也就是內表不適用索引或者索引效率很低時不得不使用到BNL 2. 對於使用到BNL特性且性能較差的SQL,建議在session級別將join_buffer_size臨時增大來提高性能

 

BKA(Batched Key Access)算法

通過緩存外層循環讀的行,來降低內層的讀取次數。例如,10行數據讀入buffer中,然后buffer被傳遞到內層循環,內層表讀出的每一行都會跟這個緩存10行依次做對比,這樣就降低了內層表數據的讀取次數

  • 出現原因:因為BNL使用條件是內表關聯字段沒有索引或效率很低才不得不使用,但大部分join通常的效率較高的索引來做ref或eq_ref方式進行連接,這種情況下BNL無法使用到。為了優化Join,引入了MRR和BKA
BAK局限性,使用BKA來做Join,很多情況下可以提高連接效率,但對Join也有一定的條件限制
1. 一個條件是連接的列要求是唯一索引或普通索引,但不能是主鍵(這也是join on條件的字段一定要加索引的原因) 2. 另一個是要有對非主鍵列的查詢操作,否則優化器就可以通過覆蓋索引直接得到需要的數據,不需要回表

 

MRR(Multi-Range Read Optimization)MRR通過把隨機磁盤讀,轉化為順序磁盤讀,從而提高了索引查詢的性能。適用於range ref eq_ref類型的查詢

  • 本質: MRR 在本質上是一種用空間換時間的算法
  • 原理:目的就是為了減少磁盤的隨機訪問,Innodb由於聚集索引的特點,如果查詢使用輔助索引,並且用到表中非索引列,那么需要回表讀取數據做后續處理,過於隨機的回表會伴隨着大量的隨機IO。而MRR的優化並不是每次通過輔助索引讀取到數據就回表,而是通過范圍掃描將數據存入read_rnd_buffer_size,然后對其按照Primary Key排序,最后使用排序好的數據進行順序回表,因為Innodb中葉子節點數據是按照PrimaryKey 排序,這樣就轉換隨機IO為順序IO了,對瓶頸為IO的SQL查詢語句將帶來極大的性能提升。

解讀:MRR的特點類似在編程中,禁止使用循環去查詢數據庫的概念。而是先將結果集查詢出來,然后通過排序,將排序的結果集存儲在緩沖區內,當緩沖區滿后,將使用該結果集再次去Mysql Server中查詢,此時的結果集是已經排好序的,查詢的時候也是順序IO,查詢速度加快,並且是一次查詢,而非N次循環查詢。

  • MRR的使用在單表和多表join查詢中都可以使用,其中,單表通常通過范圍查詢;多表join方式如果是ref/eg_ref,則先通過BKA算法批量提取key到join buffer,然后將buffer中的key作為參數傳入MRR的調用接口,MRR高效讀取需要的數據返回。當優化器使用了MRR時,執行計划的 Extra 列會出現 "Using MRR"
  • 參數read_rnd_buffer_size用來控制rowid排序的內存的大小
SQL整體過程如下:
1. 優化器通過二級索引的記錄放到一塊緩沖區中 2. 如果二級索引掃描到文件的末尾或者緩沖區已滿,則使用快速排序對緩沖區中的內容按照主鍵進行排序 3. 用戶線程調用MRR接口取cluster index,然后根據cluster index 取行數據 4. 當根據緩沖區中的 cluster index取完數據,則繼續調用過程 2) 3),直至掃描結束
BKA是MySQL5.6引入的新算法,結合MRR特性進行高效Join操作,具體操作如下
1. 將外循環表中相關的列放入JoinBuffer中 2. 批量的將Key(索引鍵值)發送到MRR接口 3. MRR通過收到的Key,根據其對應的PrimaryKey進行排序,然后再根據排序后的PrimaryKey順序讀取聚集索引,得到需要的列數據 4. 返回結果集給客戶端

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM