1. 程式人生 > >淺析MySQL中的Index Condition Pushdown (ICP 索引條件下推)和Multi-Range Read(MRR 索引多範圍查找)查詢優化

淺析MySQL中的Index Condition Pushdown (ICP 索引條件下推)和Multi-Range Read(MRR 索引多範圍查找)查詢優化

修正 itl iad 較高的 一句話 mysql5 條件篩選 global 查詢條件

本文出處:http://www.cnblogs.com/wy123/p/7374078.html
(保留出處並非什麽原創作品權利,本人拙作還遠遠達不到,僅僅是為了鏈接到原文,因為後續對可能存在的一些錯誤進行修正或補充,無他)

ICP優化原理

Index Condition Pushdown (ICP),也稱為索引條件下推,體現在執行計劃的上是會出現Using index condition(Extra列,當然Extra列的信息太多了,只能做簡單分析)
ICP原理通俗講就是,查詢過程中,直接在查詢引擎層的API獲取數據的時候實現"非直接索引"過濾條件的篩選,而不是查詢引擎層查詢出來之後在Server層篩選。

換句話說就是ICP在獲取數據的同時實現了where的次選條件中無法直接使用索引的情況下的篩選,避免了沒有ICP優化的時候分兩個步驟的實現(獲取數據的過程沒有做次選條件的過濾)
如果是非ICP優化查詢的話,是兩步,第一步是獲取數據,第二步是獲取的數據進行條件篩選。
顯然,相比後者,前者可以一步實現索引的查找Seek+filter,效率上更高。

適應的場景:
ICP的優化策略可用於range、ref、eq_ref、ref_or_null 類型的訪問數據方法

其實沒有實例不太好理解這種優化策略,還是舉兩個實際列子吧。

ICP優化實例

第一個例子在網上非常多,也非常容易理解.具體表結構見上文(http://www.cnblogs.com/wy123/p/7366486.html)

下面用到的test_orderdetail表的索引為:create index idx_orderid_productname on test_orderdetail(order_id,product_name);
查詢語句為:select * from test_orderdetail where order_id = 10900 and product_name like ‘%00163e0496af%‘;
顯然,order_id = 10900是可以直接進行索引查找的,雖然product_name也包含在復合索引中,但是product_name like ‘%00163e0496af%‘是無法使用索引的
觀察其執行計劃,發現Extra中是Using index condition。

ICP在這裏的優化原理就是,
在利用第一個條件 order_id = 10900 進行索引查找的過程中,同時使用product_name like ‘%00163e0496af%‘這個無法直接使用索引查找的條件進行過濾。
最終一步就可以篩選出來結果。

技術分享

  對比關閉ICP優化的情況
  如果關閉ICP優化,執行計劃的Extra顯示為Using where,
  意味著使用order_id = 10900進行索引查找之後,再對結果集進行product_name like ‘%00163e0496af%‘的篩選

技術分享

  

  第二個例子是後面自己想的,為了驗證ICP的出現場景,以及確實優於非ICP優化的情況

這一次使用的表是test_order,test_order上的索引為create index idx_userid_order_id_createdate on test_order(user_id,order_id,create_date);
查詢語句為:select * from test_order where user_id = 500 and create_date > ‘2015-1-1‘;
與上面的例子一樣,第二個篩選條件是無法直接使用索引的

  首先看兩者的執行計劃在ICP優化上的區別

技術分享

  關閉ICP之後的執行計劃

技術分享

  然後分別執在打開與關閉ICP的情況下,觀察其執行過程中的profile信息

技術分享

  查看兩個sql執行的詳細信息,也即分別在打開與關閉ICP優化的情況下,如下,在stage/sql/Sending data環節有超過一個數量級的差異。
  也就意味著通過ICP機制的優化,server 層和 engine 層之間數據交互的次數減少。

  技術分享

  引用MySQL · 特性分析 · Index Condition Pushdown (ICP)中的一句話:
  在二級索引是復合索引且前面的條件過濾性較低的情況下,打開 ICP 可以有效的降低 server 層和 engine 層之間交互的次數,從而有效的降低在運行時間。

  最後,再思考一個問題,
  對於select * from test_orderdetail where order_id = 10900 and product_name like ‘%00163e0496af%‘;這個查詢,
  如果order_id 包含在一個二級索引中,但是product_name 沒有包含在這個二級索引中,MySQL會不會采用ICP的方式進行優化?
  答案是否定的。
  因為ICP的前提兩個查詢條件包被索引覆蓋,但是次選條件無法直接使用索引查找,如果次選條件沒有被索引覆蓋,是無法得知次選條件的值的,也就無從 索引條件下推優化了。

  技術分享

  

Multi-Range Read(MRR)

非MRR優化下存在的問題:
首先了解一點背景知識:MySQL的Innodb表都是聚集索引表,沒有顯式指定聚集索引的情況下,會自動生成一個聚集索引。
在使用二級索引(或者說是非聚集索引)進行範圍查詢的條件下,二級索引會根據其B樹結構的葉子節點存儲的聚集索引進行數據的查找(回表操作),
但是符合條件的數據(二級索引超找的數據)有可能是隨機分布在聚集索引B樹的任何一個部分,這樣就可能存在表上過多的隨機IO。
當表非常大的時候,每一行的查找過程都需要在磁盤上隨機進行,可能會對性能造成影響。

舉個例子,
如下圖,參考藍線的移動軌跡,二級索引查找到的目標數據行的物理位置為1,2,3,4(主要的是以何種順序去獲取這四個位置的數據,可以隨機的方式獲取,也可以順序的方式獲取,講究就在這一點)
在查找這四個位置的數據的時候,如果直接按照二級索引對應的聚集索引的順序查找,
由於二級索引排序的情況下,其對應的聚集索引的順序可能是隨機的,那麽其對應的數據的物理位置也就是隨機的了
如果按照二級索引的順去回表超找對應的數據行,那麽這個過程就需要隨機IO查找。
這種查詢方式的缺點,可以理解為在查詢這四行數據的過程中,在物理位置差異較大的情況下,需要磁頭來回擺臂來實現(隨機IO讀取)。

技術分享

MRR多範圍讀取優化的目的是通過對記錄的讀取請求進行排序,然後再讀取數據行的時候以順序IO的方式進行,避免隨機IO
究竟是對哪個字段排序?個人認為可以理解成二級索引範圍查找到的對應的聚集索引的key值進行排序。
有序掃描的過程可以認為是:

(1)通過非聚集索引找到目標數據的聚集索引的key值
(2)對通過二級索引找到的目標數據的聚集索引的key值排序,此時聚集索引與物理位置一一對應。
(3)(回表的過程)通過二級索引對應的有序的聚集索引,執行一個有序的磁盤掃描來獲取數據,從而來加快讀取數據的速度。

技術分享

順序讀磁盤通常會更快,當然也不是說這種方式的效率總是較高的,凡事有利必有弊,也有例外的情況

1,如果掃描的是一個較小的數據範圍,並且目標數據已經在磁盤的緩存當中,MRR的唯一影響是為了緩沖/排序額外的增加了一些CPU開銷。
2,order by *** LIMIT n查詢,當n值比較小的時候,可能會變的更慢,
  原因是 MRR試圖通過順序讀盤的方式(來或取數據),可能一開始讀取到的數據並非總是排在(order by ***)符合前N條的。
3,MRR是一個實現過程,個人理解,極端情況下,如果MySQL不知道目標數據的行數,
  如果僅僅只有一行,依然要進行排序操作,然後回表讀取數據行,這種情況下也是得不償失的。

  打開MRR優化
  set global optimizer_switch = ‘mrr=on,mrr_cost_based=off‘;

  啟用MRR優化的前提是要進行書簽超找,也即要回表,如果不需要回表的話,二級索引本身就可以查詢出來需要的字段了,沒有隨機IO的機會的所謂了。

技術分享

  如下截圖,如果去掉order_status,也就意味著無需回表查詢,那麽就不會出現MRR優化了。

技術分享

  同時,一旦出現MRR優化,查詢出來的結果的順序,必然是按照聚集索引來排序的,這個原理應該是不難理解的。

  技術分享

  當然MRR優化也有在表關聯情況下的優化措施,原理大同小異。

總結:

    Index Condition Pushdown(索引條件下推)和Multi-Range Read(多範圍讀)都是MySQL為了提高查詢優化而備用的選項,屬於MySQL5.6裏面的新特性。
    無奈樓主接觸MySQL不久,見識不夠,很是覺得新鮮,高手勿噴。
    兩者的共同的特點都是在使用索引超找(或者索引範圍掃描)的過程中的一些優化措施。
    這些優化措施可以在二級索引查找(索引範圍掃描)的過程中優化查詢動作的行為,
    當然這些優化措施並非總是萬能的,允許用戶顯式打開或者關閉,給用戶充分的自由,然而自由也並非完全沒有問題,這也要求用戶在做相關優化的時候需要進行充分的權衡和考慮。

參考:

    https://mariadb.com/kb/en/mariadb/multi-range-read-optimization/
    http://blog.itpub.net/22664653/viewspace-1673682/
    http://blog.itpub.net/22664653/viewspace-1678779/
    http://mysql.taobao.org/monthly/2015/12/08/

    以及各種網上搜索……

最後,mariadb官方這幾張圖非常贊,對理解問題很有幫助,先盜下來,備用(無恥一笑,O(∩_∩)O~)

技術分享

技術分享技術分享

技術分享技術分享

淺析MySQL中的Index Condition Pushdown (ICP 索引條件下推)和Multi-Range Read(MRR 索引多範圍查找)查詢優化