MySQL索引命中分析和長度的計算,面試時答對了嗎?

點擊上方“統計與數據分析實戰”,選擇“設爲星標” ,質文章和資源,及時送達

今天程序猿碼不停問了個問題:在MySQL的InnoDB引擎下,有表 test,表中有索引 idx_a_b_c('a', 'b', 'c') ,那麼SQL SELECT * from test WHERE c = 1 and b > 1 and a = 1 的索引命中情況是怎樣的呢?

大家一看,這不是很普通的索引最左匹配問題嗎?首先,答案是肯定的,可以命中索引!雖然索引順序是 a、b、c,但是因爲SQL執行前,MySQL查詢優化器會判斷糾正這條sql語句該以什麼樣的順序執行效率最高,最後才生成真正的執行計劃 SELECT * from test WHERE and a = 1 and b > 1 and c = 1 。由於 b 使用了範圍查詢,所以索引只命中了 a 和 b 兩列,b 之後的 c 列不再命中。

碼不停繼續追問:嗯…… 口說無憑據,怎麼證明呢?

EXPLAIN解析

對於SQL的執行分析,我們首先想到的就是 EXPLAIN 來解析。如果你還對 EXPLAIN 不熟悉,那該補補基礎了。這裏只做一個實戰介紹,就以上述問題中的 SQL 舉例。建表語句如下:

CREATE TABLE `test` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  `c` int(11) DEFAULT NULL,
  `d` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `index_abc` (`a`,`b`,`c`) USING BTREE,
  KEY `index_ad` (`a`,`d`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC

1、執行 EXPLAIN 分析 SQL

首先,執行下面 SQL:

EXPLAIN select * from test where c = 1 and b > 1 and a = 1;

然後得到輸出:

想要分析 SQL 就需要懂得每個字段的含義

2、EXPLAIN 字段解釋

id:每個執行計劃都有一個 id,如果是一個聯合查詢,這裏還將有多個 id。

select_type:表示 SELECT 查詢類型,這條SQL 是 SIMPLE(普通查詢,即沒有聯合查詢、子查詢)類型。其他還有 PRIMARY(主查詢)、UNION(UNION 中後面的查詢)、SUBQUERY(子查詢)等。

table:當前執行計劃查詢的 test 表,如果給表起別名了,則顯示別名信息。

partitions:訪問的分區表信息。

type:表示從表中查詢到行所執行的方式,查詢方式是 SQL 優化中一個很重要的指標,結果值從好到差依次是:system > const > eq_ref > ref > range > index > ALL

system/const:表中只有一行數據匹配,此時根據索引查詢一次就能找到對應的數據。

eq_ref:使用唯一索引掃描,常見於多表連接中使用主鍵和唯一索引作爲關聯條件。

ref:非唯一索引掃描,還可見於唯一索引最左原則匹配掃描。

range:索引範圍掃描,比如,<,>,between 等操作。

index:索引全表掃描,此時遍歷整個索引樹。

ALL:表示全表掃描,需要遍歷全表來找到對應的行。

這裏因爲使用了 b > 條件,所以使用 range 類型。

possible_keys:可能使用到的索引。因爲表中還有 index_ad 索引,所以可能用到的索引是兩個。

key:實際使用到的索引。最終判斷使用索引 index_abc.。

key_len:當前使用的索引的長度。(重要!重要重要重要的事情說三遍!!!)通過 key_len 便可以判斷索引的命中情況。

ref:關聯 id 等信息。

rows:查找到記錄所掃描的行數。

filtered:查找到所需記錄佔總掃描記錄數的比例。

Extra:額外信息。

通過上述結束,每個字段我們都明白什麼含義。並且證明了雖然原始 sql 中abc的順序是亂序的,但是我們還是可以命中索引 index_abc。但是具體命中索引中的哪幾列呢?通過 key_len 又如何判斷。

索引長度計算

因爲聯合索引的結構特點, 如果命中索引,那麼命中的列只有可能是這幾種情況:a、ab、abc。就像一個鏈,你無法在跳過 b 節點的情況下找到c節點。所以現在問題就轉換成,如何確認命中索引 index_abc 是命中了 a 列、ab列 還是 abc 列。想要會分析,就需要掌握索引長度的計算方法了。

1、索引長度公式

1.所有的索引字段,如果沒有設置not null,則需要加一個字節。 

2.定長字段,int佔四個字節、date佔三個字節、char(n)佔n個字符。 

3.對於變成字段varchar(n),則有n個字符+兩個字節。 

4.不同的字符集,一個字符佔用的字節數不同。latin1編碼的,一個字符佔用一個字節,gbk編碼的,一個字符佔用兩個字節,utf8編碼的,一個字符佔用三個字節。 

5.索引長度 char()、varchar()索引長度的計算公式:

Character Set:utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列長度 + 1(允許null) + 2(變長列)

2、舉例:

1.SQL SELECT * from test WHERE c = 1 and b = 1 and a = 1 解析:

key_len = 4 (a是int類型 4字節)+ 1a可爲null 1字節 + 4(bint類型 4字節 + 1(b可爲null 1字節 + 4(cint類型 4字節 + 1(c可爲null 1字節 = 15

2.SQL SELECT * from test WHERE b = 4 and d = c 解析:

key_len = 20(utf8每個字符 3字節) * 3 + 2(varchar) + 1(d可爲null) + 4 (a是int類型 4字節)+ 1a可爲null 1字節 = 68

3、確定命中列

explain 的結果 key_len 長度是 10,怎麼得出來的呢?套用公式。

4 (a是int類型 4字節)+ 1a可爲null 1字節 + 4(bint類型 4字節 + 1(b可爲null 1字節 = 10  

所以,我們得出最終結論,SQL SELECT * from test WHERE c = 1 and b > 1 and a = 1 命中了索引 index_abc 的 a和b列!

看到這裏,碼不停同學點了點頭。

◆ ◆ ◆  ◆ 

關注並後臺回覆 “面試” 或者  “資料

即可免費獲取最新2019BAT

大廠面試題和大數據視頻

如果文章有幫助到你,請點擊再看或者轉發支持!


送書啦~

規則:公衆號後臺會自動統計分享榜排名,第一名即可包郵獲得此書。


更多書籍請戳:優質圖書

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章