10 分鐘搞明白 MySQL 是如何利用索引的!

1、前言

在MySQL中進行SQL優化的時候,常常會在一些狀況下,對MySQL可否利用索引有一些迷惑。html

譬如:java

  1. MySQL 在遇到範圍查詢條件的時候就中止匹配了,那麼究竟是哪些範圍條件?mysql

  2. MySQL 在LIKE進行模糊匹配的時候又是如何利用索引的呢?spring

  3. MySQL 到底在怎麼樣的狀況下可以利用索引進行排序?sql

今天,我將會用一個模型,把這些問題都一一解答,讓你對MySQL索引的使用再也不畏懼數據庫

2、知識補充

key_len

EXPLAIN執行計劃中有一列 key_len 用於表示本次查詢中,所選擇的索引長度有多少字節,一般咱們可藉此判斷聯合索引有多少列被選擇了。intellij-idea

在這裏 key_len 大小的計算規則是:ide

  • 通常地,key_len 等於索引列類型字節長度,例如int類型爲4 bytes,bigint爲8 bytes;spring-boot

  • 若是是字符串類型,還須要同時考慮字符集因素,例如:CHAR(30) UTF8則key_len至少是90 bytes;性能

  • 若該列類型定義時容許NULL,其key_len還須要再加 1 bytes;

  • 若該列類型爲變長類型,例如 VARCHAR(TEXT\BLOB不容許整列建立索引,若是建立部分索引也被視爲動態列類型),其key_len還須要再加 2 bytes;

3、哪些條件能用到索引

首先很是感謝登博,給了我一個很好的啓發,我經過_他的文章_,而後結合本身的理解,製做出了這幅圖

MySQL where條件剖析

乍一看,是否是很暈,不急,咱們慢慢來看

圖中一共分了三個部分:

  1. Index Key :MySQL是用來肯定掃描的數據範圍,實際就是能夠利用到的MySQL索引部分,體如今Key Length。

  2. Index Filter:MySQL用來肯定哪些數據是能夠用索引去過濾,在啓用ICP後,能夠用上索引的部分。

  3. Table Filter:MySQL沒法用索引過濾,回表取回行數據後,到server層進行數據過濾。

咱們細細展開。

Index Key

Index Key是用來肯定MySQL的一個掃描範圍,分爲上邊界和下邊界。

MySQL利用=、>=、> 來肯定下邊界(first key),利用最左原則,首先判斷第一個索引鍵值在where條件中是否存在,若是存在,則判斷比較符號,若是爲(=,>=)中的一種,加入下邊界的界定,而後繼續判斷下一個索引鍵,若是存在且是(>),則將該鍵值加入到下邊界的界定,中止匹配下一個索引鍵;若是不存在,直接中止下邊界匹配。

exp:
idx_c1_c2_c3(c1,c2,c3)
where c1>=1 and c2>2 and c3=1
--> first key (c1,c2)
--> c1爲 '>=' ,加入下邊界界定,繼續匹配下一個
-->c2 爲 '>',加入下邊界界定,中止匹配

上邊界(last key)和下邊界(first key)相似,首先判斷是不是否是(=,<=)中的一種,若是是,加入界定,繼續下一個索引鍵值匹配,若是是(<),加入界定,中止匹配

exp:
idx_c1_c2_c3(c1,c2,c3)
where c1<=1 and c2=2 and c3<3
--> last key (c1,c2,c3)
--> c1爲 '<=',加入上邊界界定,繼續匹配下一個
--> c2爲 '='加入上邊界界定,繼續匹配下一個
--> c3 爲 '<',加入上邊界界定,中止匹配

注:這裏簡單的記憶是,若是比較符號中包含'='號,'>='也是包含'=',那麼該索引鍵是能夠被利用的,能夠繼續匹配後面的索引鍵值;若是不存在'=',也就是'>','<',這兩個,後面的索引鍵值就沒法匹配了。同時,上下邊界是不能夠混用的,哪一個邊界能利用索引的的鍵值多,就是最終可以利用索引鍵值的個數。

Index Filter

字面理解就是能夠用索引去過濾。也就是字段在索引鍵值中,可是沒法用去肯定Index Key的部分。

exp:
idex_c1_c2_c3
where c1>=1 and c2<=2 and c3 =1
index key --> c1
index filter--> c2 c3

這裏爲何index key 只是c1呢?由於c2 是用來肯定上邊界的,可是上邊界的c1沒有出現(<=,=),而下邊界中,c1是>=,c2沒有出現,所以index key 只有c1字段。c2,c3 都出如今索引中,被當作index filter.

Table Filter

沒法利用索引完成過濾,就只能用table filter。此時引擎層會將行數據返回到server層,而後server層進行table filter。

4、Between 和Like 的處理

那麼若是查詢中存在between 和like,MySQL是如何進行處理的呢?

Between

where c1 between 'a' and 'b' 等價於 where c1>='a' and c1 <='b',因此進行相應的替換,而後帶入上層模型,肯定上下邊界便可

Like

首先須要確認的是%不能是最在最左側,where c1 like '%a' 這樣的查詢是沒法利用索引的,由於索引的匹配須要符合最左前綴原則

where c1 like 'a%' 其實等價於 where c1>='a' and c1<'b' 你們能夠仔細思考下。

5、索引的排序

在數據庫中,若是沒法利用索引完成排序,隨着過濾數據的數據量的上升,排序的成本會愈來愈大,即便是採用了limit,可是數據庫是會選擇將結果集進行所有排序,再取排序後的limit 記錄,並且MySQL 針對能夠用索引完成排序的limit 有優化,更能減小成本。

Make sure it uses index It is very important to have ORDER BY with LIMIT executed without scanning and sorting full result set, so it is important for it to use index – in this case index range scan will be started and query execution stopped as soon as soon as required amount of rows generated.

CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c1` int(11) NOT NULL DEFAULT '0',
  `c2` int(11) NOT NULL DEFAULT '0',
  `c3` int(11) NOT NULL DEFAULT '0',
  `c4` int(11) NOT NULL DEFAULT '0',
  `c5` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx_c1_c2_c3` (`c1`,`c2`,`c3`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4

 select * from t1;
+----+----+----+----+----+----+
| id | c1 | c2 | c3 | c4 | c5 |
+----+----+----+----+----+----+
|  1 |  3 |  3 |  2 |  0 |  0 |
|  2 |  2 |  4 |  5 |  0 |  0 |
|  3 |  3 |  2 |  4 |  0 |  0 |
|  4 |  1 |  3 |  2 |  0 |  0 |
|  5 |  1 |  3 |  3 |  0 |  0 |
|  6 |  2 |  3 |  5 |  0 |  0 |
|  7 |  3 |  2 |  6 |  0 |  0 |
+----+----+----+----+----+----+
7 rows in set (0.00 sec)

 select c1,c2,c3 from t1;
+----+----+----+
| c1 | c2 | c3 |
+----+----+----+
|  1 |  3 |  2 |
|  1 |  3 |  3 |
|  2 |  3 |  5 |
|  2 |  4 |  5 |
|  3 |  2 |  4 |
|  3 |  2 |  6 |
|  3 |  3 |  2 |
+----+----+----+
7 rows in set (0.00 sec)

存在一張表,c1,c2,c3上面有索引,select c1,c2,c3 from t1; 查詢走的是索引全掃描,所以呈現的數據至關於在沒有索引的狀況下select c1,c2,c3 from t1 order by c1,c2,c3; 的結果
所以,索引的有序性規則是怎麼樣的呢?

c1=3 —> c2 有序,c3 無序
c1=3,c2=2 — > c3 有序
c1 in(1,2) —> c2 無序 ,c3 無序

有個小規律,idx_c1_c2_c3,那麼如何肯定某個字段是有序的呢?c1 在索引的最前面,確定是有序的,c2在第二個位置,只有在c1 惟一肯定一個值的時候,c2纔是有序的,若是c1有多個值,那麼c2 將不必定有序,同理,c3也是相似

6、小結

針對MySQL索引,我這邊只是提到了在單表查詢狀況下的模型,經過這篇文章,想必你們應該瞭解到MySQL大部分狀況下是如何利用索引的,若是存在疑問,歡迎聯繫我?

做者:Harvey
來源:https://www.fordba.com/spend-10-min-to-understand-how-mysql-use-index.html
近期熱文推薦:

1.Java 15 正式發佈, 14 個新特性,刷新你的認知!!

2.終於靠開源項目弄到 IntelliJ IDEA 激活碼了,真香!

3.我用 Java 8 寫了一段邏輯,同事直呼看不懂,你試試看。。

4.吊打 Tomcat ,Undertow 性能很炸!!

5.《Java開發手冊(嵩山版)》最新發布,速速下載!

以爲不錯,別忘了隨手點贊+轉發哦!

相關文章
相關標籤/搜索