1. 程式人生 > >關於mysql最左字首原則

關於mysql最左字首原則

背景知識:

  1. mysql中可以使用explain關鍵字來檢視sql語句的執行計劃。
  2. 最左字首原則主要使用在聯合索引中
  3. 資料庫版本Mysql5.5.53

1.首先準備如下測試資料表

CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  `school` char(20) NOT NULL DEFAULT '',
  KEY `name_cid_INX` (`name`,`cid`,`school`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert into student values
(1,'weixin',12,'ningbo'),
(2,'weixin',13,'ningbo'),
(3,'weixin',14,'ningbo');

2.我看了很多網上對字首原則的說明,例如abc聯合索引,只有當a或者ab或者abc為條件時才能觸發索引,這當然是毋容置疑的,但是我測試了發現ac也是會觸發聯合索引的,這是為什麼呢?

 

我把重點放在了key_len這一項上,key_len是指索引型別的位元組長度,那麼上面768是怎麼計算得到的呢?name列申明的是255,而且字符集是utf8,因此初步計算可以得到值為255*3=765,由於varchar有一個特性就是超過255(應該也包括255)會額外使用兩個位元組記錄長度,因此765還需要加上2,也就是767,又因為name列為null,所以mysql需要1個位元組來標識NULL,因此可以計算得出最後結果為768。同理cid列可以計算得到為4+1=5,school列計算得到為20*3=60,那麼一個聯合索引按照key_len的定義上理解的話,name_cid_INX應該是768+5+60=833,但是為什麼ac條件下觸發了聯合索引,key_len卻只是768,網上查了資料發現聯合索引可以使用部分,這也是為什麼要遵循字首原則的原因。

鑑於聯合索引可以使用部分的原因,猜測ac條件之所以觸發了聯合索引是因為它與單獨使用a條件相同,為此對比只使用a條件的情況,具體如下:

發現key_len與ac條件下一致,即驗證猜測。接下來我們依次看一下ab和abc條件使用聯合索引的情況:

根據以上表述,我們可以得出如下結論:當使用abc會完全使用聯合索引的abc三列,使用ab只會使用聯合索引中的兩列,使用a或者ac只會使用聯合索引中的a列,至於其他情況聯合索引不會被使用。

3.注意點:細心的讀者可能會發現,我們插入的測試資料name都是"weixin"但是查詢的時候卻沒有使用name="weixin"而是使用了name="weixi",原因就是當name="weixin"時命中了表中的大部分資料,mysql查詢優化器認為全表掃描比索引索引掃描效率更高而選擇了全表掃描,如下:

還有關於mysql的查詢優化器還有一點需要注意,sql語句中欄位的順序不需要和聯合索引中定義的欄位順序一致,查詢優化器會自己調整順序: