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

来源:http://www.cnblogs.com/wy123/archive/2017/08/16/7374078.html
-Advertisement-
Play Games

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


 

本文出處: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~),

突然又想到做人了,為什麼一定要直來直去呢,很多時候是欲速則不達,迂迴一下,暫時停下來,好好計劃計劃再出發,未必是壞事。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前提條件,存在A和B兩個頁面,A是主界面,A push 到 B 方法一:如果B頁面的返回按鈕要用自定義的按鈕(在iOS7中,如果使用了UINavigationController,那麼系統自帶的附加了一個從屏幕左邊緣開始滑動可以實現pop的手勢。但是,如果自定義了navigationItem的lef ...
  • 本文是根據文頂頂老師的博客學習而來,轉載地址:http://www.cnblogs.com/wendingding/p/3809042.html 一、NSOperation簡介 1.簡單說明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能實現多線程 ...
  • 最近自己在做一個小說閱讀器,看到某閱有護眼模式功能,別人都有,我怎麼能沒有? <! more 現在這功能已經不稀奇了,很多手機都帶有這個功能。 實現起來不難,用一個蒙版遮在界面上面就行。 至於蒙版,可以用Window實現,也可以只用套個FrameLayout實現。 Window實現的優點是,支持全局 ...
  • 報錯原因是 項目使用的是ARC,但是有非ARC代碼。 項目中要混合使用ARC和非ARC。 解決: 如果使用的非 ARC ,則為 ARC 的代碼加入 -fobjc-arc 如果使用的是 ARC ,則為非 ARC 代碼加入 -fno-objc-arc 判斷項目是否用的ARC: 如果使用的非 ARC ,則 ...
  • http://bbs.gfan.com/android-6740350-1-1.html 原創處女貼,呵呵。。。 研究換4.1.2也有段時間了,4.1.2各方面功能均讓我挺滿意的,用著也蠻順手的。偶爾上論壇,看到有人說,4.1.2存在媒體掃描耗電的bug,當時我還不以為然,也慶幸自己的這個版本沒有問 ...
  • 代碼: ViewController.m ...
  • 介於上一篇的java實現網路爬蟲基礎之上,這一篇的思想是將網路收集的數據保存到HDFS和資料庫(Mysql)中;然後用MR對HDFS的數據進行索引處理,處理成倒排索引;搜索時先用HDFS建立好的索引來搜索對應的數據ID,根據ID從資料庫中提取數據,呈現到網頁上。 這是一個完整的集合網路爬蟲、資料庫、 ...
  • 一 使用IN關鍵字的子查詢 1.查詢游戲類型是'棋牌類' 的游戲的分數信息 游戲分數表中並未包含游戲類型信息 思路一:採用鏈接查詢 思路二: 分兩步進行,首先找到所以'棋牌類'游戲的編號,再以這一組編號為查詢依據完成查詢 select * from scores where gno in (sele ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...