MySQL Execute Plan--Index Merge特性

来源:https://www.cnblogs.com/gaogao67/archive/2020/01/08/12167967.html
-Advertisement-
Play Games

Index Merge特性 在MySQL 5.5之前版本中,查詢或子查詢被限制在一個表只能使用一個索引(回表查詢除外)。 假設表TB1001上C1和C2列分別有單列索引,如對下麵查詢: SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX'; 單獨使用任一索引 ...


Index Merge特性

在MySQL 5.5之前版本中,查詢或子查詢被限制在一個表只能使用一個索引(回表查詢除外)。

假設表TB1001上C1和C2列分別有單列索引,如對下麵查詢:

SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX';

單獨使用任一索引都無法獲取到所有滿足條件的數據,因此查詢只能使用全表掃描。

在MySQL 5.5版本中引入Index Merge特性,允許:
查詢對一個表上多個索引進行範圍掃描並將多個掃描結果進行合併(UNION/INTERSECT)。

Index Merge三種合併演算法:

1Index Merge Intersect:對多個結果集求交集
2Index Merge Union:對多個結果集求UNION集合(無需對結果集排序)
3Index Merge Sort-Union:對多個結果集先排序再求UNION集合

 

 

Index Merge Intersect演算法

當查詢過濾條件(WHERE部分)上使用AND關聯多個不同KEY的過濾條件時,如:

# 表TB1001有主鍵索引PRIMARY KEY(ID)
# 表TB1001有輔助索引IDX_C1(C1) 和輔助索引IDC_C2(C2)

SELECT * FROM TB1001 WHERE C1='XXX' AND C2='XXX';

不使用Index Merge Intersect演算法時執行計劃偽代碼為:

SELECT * FROM TB1001
WHERE ID IN (
SELECT ID FROM TB1001 WHERE C1='XXX')
AND C2='XXX';

使用Index Merge Intersect演算法時執行計劃偽代碼為:

SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1='XXX'
INTERSECT
SELECT ID FROM TB1001 WHERE C2='XXX'
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID;

 

操作成本假設1:

假設:
滿足C1='XXX'的記錄有10000行:索引IDX_C1上每個數據頁存放500行索引記錄,滿足條件數據:
    A、"順序存放"在索引IDX_C1上"連續"的20個索引頁中。
    B、"分散存放"在主鍵上"隨機"的2000個數據頁中。
滿足C2='XXX'的記錄有20000行,索引IDX_C2上每個數據頁存放500行索引記錄,滿足條件數據:
    A、"順序存放"在索引IDX_C2上"連續"的40個索引頁中。
    B、"分散存放"在主鍵上"隨機"的4000個數據頁中。
同時滿足C1='XXX' AND C2='XXX'的記錄有200行,滿足條件數據:
    A、"分散存放"在主鍵上"隨機"的40個數據頁中

那麼:
1、不使用Index Merge Intersect演算法需要"順序讀取"20個IDX_C1索引頁+"隨機讀取"2000個主鍵索引數據頁
2、使用Index Merge Intersect演算法需要"順序讀取"20個IDX_C1索引頁+"順序讀取"40個IDX_C2索引頁+"隨機讀取"40個主鍵索引數據頁
針對上面情況,使用Index Merge Intersect演算法能有效降低對主鍵的回表查找次數和隨機讀取次數(從2000次下降至40次)。


操作成本假設2:

假設:
滿足C1='XXX'的記錄有20行:索引IDX_C1上每個數據頁存放500行索引記錄,滿足條件數據:
    A、"順序存放"在索引IDX_C1上"連續"的1個索引頁中。
    B、"分散存放"在主鍵上"隨機"的20個數據頁中。
滿足C2='XXX'的記錄有200000行,索引IDX_C2上每個數據頁存放500行索引記錄,滿足條件數據:
    A、"順序存放"在索引IDX_C2上"連續"的400個索引頁中。
    B、"分散存放"在主鍵上"隨機"的40000個數據頁中。
同時滿足C1='XXX' AND C2='XXX'的記錄有19行,滿足條件數據:
    A、"分散存放"在主鍵上"隨機"的19個數據頁中

那麼:
1、不使用Index Merge Intersect演算法需要"順序讀取"1個IDX_C1索引頁+"隨機讀取"20個主鍵索引數據頁
2、使用Index Merge Intersect演算法需要"順序讀取"1個IDX_C1索引頁+"順序讀取"400個IDX_C2索引頁+"隨機讀取"19個主鍵索引數據頁
針對上面情況,使用Index Merge Intersect演算法需要額外讀取400個IDX_C2索引頁才能降低1次主鍵的回表查詢和隨機讀取,顯然性能更差。


Index Merge Intersect演算法和Index condition Pushdown特性

在MySQL官方文檔中,Index Merge Intersect演算法可以應用在分別使用主鍵和二級索引的查詢中,如:

SELECT *
FROM innodb_table
WHERE primary_key < 10
AND key_col1 = 20;

 

在未引入ICP特性的早期MySQL版本中,主鍵上過濾條件(primary_key < 10)不會"下推"到查詢滿足key_col1 = 20條件的過程中,因此可以使用Index Merge Intersect演算法來減少回表查找次數。

在引入ICP特性的MySQL版本中,由於輔助索引的索引記錄中都包含主鍵列數據,因此主鍵上過濾條件(primary_key < 10)可以"下推"到查詢滿足key_col1 = 20條件的過程中,無需再使用Index Merge Intersect演算法。

## 在MySQL 5.7版本中測試
SELECT *
FROM TB001
WHERE C1=10
AND ID<100;
## 執行計劃為:
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: TB001
   partitions: NULL
         type: ref
possible_keys: PRIMARY,IDX_C1
          key: IDX_C1
      key_len: 5
          ref: const
         rows: 1
     filtered: 33.33
        Extra: Using where; Using index
## 執行計劃Extra部分沒有INDEX MERGE相關信息

 

Index Merge Intersect性能問題優化

 

在部分場景中,使用Index Merge Intersec演算法會帶來嚴重的性能問題,DBA可以通過MySQL參數optimizer_switch來關閉該特性。

對於通過Index Merge Intersec演算法受益的查詢,可以考慮使用組合索引或覆蓋索引來替換單列索引。

如對上面查詢,可以將索引IDX_C1(C1)調整為IDX_C1_C2(C1,C2),其查詢性能更佳。

 

 

Index Merge Union演算法
當查詢過濾條件(WHERE部分)上使用OR關聯多個不同KEY的過濾條件時,如:

# 表TB1001有主鍵索引PRIMARY KEY(ID)
# 表TB1001有輔助索引IDX_C1(C1) 和輔助索引IDC_C2(C2)
SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX';

其操作步驟為:

1、使用IDX_C1索引獲取到滿足條件的[C1,ID]記錄,記錄預設按照ID排序
2、使用IDX_C1索引獲取到滿足條件的[C1,ID]記錄,記錄預設按照ID排序
3、將已經按照ID排序的步驟1和步驟2的數據進行合併去重ID。
4、按照ID回表查找並返回

偽代碼為:

SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1='XXX'
UNION
SELECT ID FROM TB1001 WHERE C2='XXX'
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID

在創建索引IDX_C1(ID)時,其等價為IDX_C1(C1,ID),相同C1值的記錄按ID值排序,因此UNION操作的兩個中見結果集在ID上時有序的。

 

Index Merge Sort-Union演算法

當查詢過濾條件(WHERE部分)上使用OR關聯多個不同KEY的過濾條件時,如:

# 表TB1001有主鍵索引PRIMARY KEY(ID)
# 表TB1001有輔助索引IDX_C1(C1) 和輔助索引IDC_C2(C2)
SELECT * FROM TB1001 WHERE C1>'XXX' OR C2<'XXX';

其操作步驟為:

1、使用IDX_C1索引獲取到滿足條件的[C1,ID]記錄,再按照ID進行排序
2、使用IDX_C1索引獲取到滿足條件的[C1,ID]記錄,再按照ID進行排序
3、將步驟1和步驟2的已按ID排序後數據進行合併去重ID。
4、按照ID回表查找並返回

偽代碼為:

SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1>'XXX'
ORDER BY ID
UNION
SELECT ID FROM TB1001 WHERE C2>'XXX'
ORDER BY ID
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID

在創建索引IDX_C1(ID)時,其等價為IDX_C1(C1,ID),對C1列進行範圍查詢返回數據的數據按照C1+ID排序,在ID列上是無序的,因此UNION操作前需先對兩個中間結果集排序。


Index Merge Union相關優化
在禁用Index Merge特性時,可以通過SQL將OR操作改寫為UNION ALL操作,使查詢同時使用多個索引。

如上面使用Index Merge Union演算法的查詢,可以改寫為:

#改寫前:
SELECT * FROM TB1001 WHERE C1='XXX' OR C2='XXX';

# 改寫後
SELECT T2.* FROM (
SELECT ID FROM TB1001 WHERE C1='XXX'
UNION ALL
SELECT ID FROM TB1001 WHERE C2='XXX' AND (C1<>'XXX' OR C1 IS NULL)
) AS T1
INNER JOIN TB1001 AS T2
ON T1.ID=T2.ID

PS: 將IDX_C2(C2)改寫為IDX_C2_C2(C1,C2)能在UNION操作前避免回表查詢。


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

-Advertisement-
Play Games
更多相關文章
  • 最近windows上需要配置全局代理 走 socks5,發現同類型的有 cow pcap 等解決方案,通過嘗試發現還是proxifier 比較好用! 下載:https://www.proxifier.com/download/legacy/ProxifierSetup331.exe 註冊: 激活ke ...
  • 安裝IIS7 1、打開伺服器管理器(開始-電腦-右鍵-管理-也可以打開),添加角色 直接下一步 勾選Web伺服器(IIS),下一步,有個註意事項繼續下一步(這裡我就不截圖了) 勾選ASP.NET會彈出以下視窗添加所需的角色服務,勾選CGI(這裡根據個人情況勾選,CGI是必選的,否則PHP不生效的) ...
  • 一、原理 1、Hypervisor是一種運行在物理伺服器和操作系統之間的中間軟體層,可允許多個操作系統和應用共用一套基礎物理硬體,它能直接訪問物理設備,會給每一臺虛擬機分配記憶體、CPU、網路、磁碟等資源,也可以確保虛擬機對應的硬體資源不被其他虛擬機訪問,是所有虛擬化技術的核心。 2、虛擬機 指通過軟 ...
  • 關於日誌切割 日誌文件包含了關於系統中發生的事件的有用信息,在排障過程中或者系統性能分析時經常被用到。對於忙碌的伺服器,日誌文件大小會增長極快,伺服器會很快消耗磁碟空間,這成了個問題。除此之外,處理一個單個的龐大日誌文件也常常是件十分棘手的事。logrotate是個十分有用的工具,它可以自動對日誌進 ...
  • test簡介 測試命令test用於形成一個表達式,結合條件判斷語句if-else來判斷。 例如可以判斷某個文件是否存在,是否具備什麼樣的特性(可讀嗎?可寫嗎?可執行嗎?塊文件嗎?)等等。 測試命令test有三種語法格式: test EXPRESSION [ EXPRESSION ] [[ EXPRE ...
  • Delete ms-resource:AppName/Text ...
  • 背景 By 魯迅 By 高爾基 說明: 1. Kernel版本:4.14 2. ARM64處理器,Contex A53,雙核 3. 使用工具:Source Insight 3.5, Visio 1. 概述 是一種物理地址反向映射虛擬地址的方法。 映射 頁表用於虛擬地址到物理地址映射,其中的 頁表項記 ...
  • Mysql存儲引擎 1.MyISAM MySQL 5.0 之前的預設資料庫引擎,最為常用。擁有較高的插入,查詢速度,但不支持事務. 2.InnoDB事務型資料庫的首選引擎,支持ACID事務,支持行級鎖定, MySQL 5.5 起成為預設資料庫引擎. 3.BDB源 自 Berkeley DB,事務型數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...