1. 程式人生 > 資料庫 >MySQL索引的使用是怎麼樣的?5個點輕鬆掌握!

MySQL索引的使用是怎麼樣的?5個點輕鬆掌握!

一、前言

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

譬如:

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

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

  3. MySQL 到底在怎麼樣的情況下能夠利用索引進行排序?

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

二、知識補充

key_len

EXPLAIN執行計劃中有一列 key_len 用於表示本次查詢中,所選擇的索引長度有多少位元組,通常我們可藉此判斷聯合索引有多少列被選擇了。

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

  • 一般地,key_len 等於索引列型別位元組長度,例如int型別為4 bytes,bigint為8 bytes;

  • 如果是字串型別,還需要同時考慮字符集因素,例如:CHAR(30) UTF8則key_len至少是90 bytes;

  • 若該列型別定義時允許NULL,其key_len還需要再加 1 bytes;

  • 若該列型別為變長型別,例如 VARCHAR(TEXT\BLOB不允許整列建立索引,如果建立部分索引也被視為動態列型別),其key_len還需要再加 2 bytes;

三、哪些條件能用到索引

首先非常感謝登博,給了我一個很好的啟發,我通過他的文章_,然後結合自己的理解,製作出了這幅圖:

 

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

 圖中一共分了三個部分:

  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。

四、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' 大家可以仔細思考下。

五、索引的排序

在資料庫中,如果無法利用索引完成排序,隨著過濾資料的資料量的上升,排序的成本會越來越大,即使是採用了limit,但是資料庫是會選擇將結果集進行全部排序,再取排序後的limit 記錄,而且MySQL 針對可以用索引完成排序的limit 有優化,更能減少成本。

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也是類似

六、小結

針對MySQL索引,我這邊只是提到了在單表查詢情況下的模型,通過這篇文章,想必大家應該瞭解到MySQL大部分情況下是如何利用索引的。

歡迎關注公眾號:程式設計師追風,領取Java知識點學習思維導圖總結+一線大廠Java面試題總結+一份300頁pdf文件的Java核心知識點總結!