【轉】mysql索引最左匹配原則的理解

做者:沈傑mysql

連接:https://www.zhihu.com/question/36996520/answer/93256153算法

來源:知乎sql

 

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `name_cid_INX` (`name`,`cid`),
  KEY `name_INX` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8

執行1:數據結構

EXPLAIN SELECT * FROM student WHERE    name='小紅';

執行2:ide

EXPLAIN SELECT * FROM student WHERE   cid=1;

EXPLAIN SELECT * FROM student WHERE   cid=1 AND name='小紅';

爲何還能匹配索引?
 

你的疑問是:sql查詢用到索引的條件是必需要遵照最左前綴原則,爲何上面兩個查詢還能用到索引?
---------------------------------------------------------------------------------------------------------------------------mysql索引

講上面問題以前,我先補充一些知識,由於我以爲你對索引理解是狹隘的:
上述你的兩個查詢的explain結果中顯示用到索引的狀況類型是不同的。,可觀察explain結果中的type字段。你的查詢中分別是:
1. type: index
2. type: ref 優化

解釋:
index:這種類型表示是mysql會對整個該索引進行掃描。spa

     要想用到這種類型的索引,對這個索引並沒有特別要求,只要是索引,或者某個複合索引的一部分,mysql均可能會採用index類型的方式掃描。code

          可是呢,缺點是效率不高,mysql會從索引中的第一個數據一個個的查找到最後一個數據,直到找到符合判斷條件的某個索引。blog

因此:對於你的第一條語句:
EXPLAIN SELECT * FROM student WHERE   cid=1;

判斷條件是cid=1,而cid是(name,cid)複合索引的一部分,沒有問題,能夠進行index類型的索引掃描方式。explain顯示結果使用到了索引,是index類型的方式。

---------------------------------------------------------------------------------------------------------------------------

ref:這種類型表示mysql會根據特定的算法快速查找到某個符合條件的索引,而不是會對索引中每個數據都進行一 一的掃描判斷,也就是所謂你日常理解的使用索引查詢會更快的取出數據。

   而要想實現這種查找,索引倒是有要求的,要實現這種能快速查找的算法,索引就要知足特定的數據結構。

       簡單說,也就是索引字段的數據必須是有序的,才能實現這種類型的查找,才能利用到索引。


有些瞭解的人可能會問,索引不都是一個有序排列的數據結構麼。不過答案說的還不夠完善,那只是針對單個索引,而複合索引的狀況有些同窗可能就不太瞭解了。

下面就說下複合索引:
以該表的(name,cid)複合索引爲例,它內部結構簡單說就是下面這樣排列的:
 

mysql建立複合索引的規則是首先會對複合索引的最左邊的,也就是第一個name字段的數據進行排序,在第一個字段的排序基礎上,而後再對後面第二個的cid字段進行排序。

其實就至關於實現了相似 order by name cid這樣一種排序規則。

因此:第一個name字段是絕對有序的,而第二字段就是無序的了。

        因此一般狀況下,直接使用第二個cid字段進行條件判斷是用不到索引的,固然,可能會出現上面的使用index類型的索引。

        這就是所謂的mysql爲何要強調最左前綴原則的緣由。

那麼何時才能用到呢?
    固然是cid字段的索引數據也是有序的狀況下才能使用咯,何時纔是有序的呢?
    觀察可知,固然 是在name字段是等值匹配的狀況下,cid纔是有序的。
    發現沒有,觀察兩個name名字爲 c 的cid字段是否是有序的呢。從上往下分別是4 5。
     這也就是mysql索引規則中要求複合索引要想使用第二個索引,必須先使用第一個索引的緣由。(並且第一個索引必須是等值匹配)。
---------------------------------------------------------------------------------------------------------------------------
因此對於你的這條sql查詢:
EXPLAIN SELECT * FROM student WHERE   cid=1 AND name='小紅';
沒有錯,並且複合索引中的兩個索引字段都能很好的利用到了!由於語句中最左面的name字段進行了等值匹配,因此cid是有序的,也能夠利用到索引了。

你可能會問

     我建的索引是(name,cid)。

     而我查詢的語句是cid=1 AND name='小紅'; 我是先查詢cid,再查詢name的,不是先從最左面查的呀?

     好吧,我再解釋一下這個問題:首先能夠確定的是把條件判斷反過來變成這樣 name='小紅' and cid=1; 最後所查詢的結果是同樣的。
         那麼問題產生了?既然結果是同樣的,到底以何種順序的查詢方式最好呢?

因此  
   而此時那就是咱們的mysql查詢優化器該登場了,mysql查詢優化器會判斷糾正這條sql語句該以什麼樣的順序執行效率最高,最後才生成真正的執行計劃。
         因此, 固然是咱們能儘可能的利用到索引時的查詢順序效率最高咯,因此mysql查詢優化器會最終以這種順序進行查詢執行。
 

做者:沈傑連接:https://www.zhihu.com/question/36996520/answer/93256153來源:知乎

相關文章
相關標籤/搜索