mysql最左側原則的深入理解

2021-09-22 02:45:40 字數 4781 閱讀 8979

一直以來,博主對最左側原則的理解都是,比如給a,b,c加上索引,那麼a,b可以用到索引,a,c也可以用到索引,但b,c是用不到的。包括這個a必須要在用到的第乙個索引處。但是如果乙個表中只有a,b,c三個字段,給他們加上聯合索引(a,b,c),此時

select * from test where c=2;
可以用到索引嗎? 在博主原來的理解中,可能毫不猶豫的就說用不到,為什麼,因為沒有根據聯合索引的最左側原則。但是事實上呢?一起來看下。

舉個例子:

對於聯合索引(col1,col2,col3),查詢語句select * from test where col2=2;是否能夠觸發索引?

大多數人都會說no,實際上卻是yes。

原因:

explain select * from test where col2=2;

explain select * from test where col1=1;

觀察上述兩個explain結果中的type字段。查詢中分別是:

type: index

type: ref

如果表中的字段除了(col1,col2,col3),還有別的字段。那麼的explain中結果將不會是index而是all。如果表中的字段只有(col1,col2,col3),那麼的explain中結果才會是index,這種情況用到了mysql的覆蓋索引。至於什麼是覆蓋索引,咱們下面再說。

根據上面的意思,我們可以知道,直接select * from test where c=2;是可以用到索引的,但是為什麼在執行計畫中的展現不同?乙個是index,乙個ref呢?雖然用到了索引,但這個索引是聯合索引嗎?

參考:這是你的表結構,有三個字段,分別是id,name,cid

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`),

) engine=innodb auto_increment=8 default charset=utf8『』

索引方面:id是主鍵,(name,cid)是乙個多列索引。

下面是你有疑問的兩個查詢:

explain select * from student where   cid=1;

explain select * from student where cid=1 and name='小紅';

你的疑問是:sql查詢用到索引的條件是必須要遵守最左字首原則,為什麼上面兩個查詢還能用到索引?講上面問題之前,我先補充一些知識,因為我覺得你對索引理解是狹隘的:

上述你的兩個查詢的explain結果中顯示用到索引的情況型別是不一樣的。可觀察explain結果中的type字段。你的查詢中分別是:

1、type: index

解釋:index:這種型別表示是mysql會對整個該索引進行掃瞄。要想用到這種型別的索引,對這個索引並無特別要求,只要是索引,或者某個復合索引的一部分,mysql都可能會採用index型別的方式掃瞄。但是呢,缺點是效率不高,mysql會從索引中的第乙個資料乙個個的查詢到最後乙個資料,直到找到符合判斷條件的某個索引。所以:對於你的第一條語句:explain select * from student where cid=1;判斷條件是cid=1,cid(name,cid)復合索引的一部分,沒有問題,可以進行index型別的索引掃瞄方式。explain顯示結果使用到了索引,是index型別的方式。

2、ref:

解釋:這種型別表示mysql會根據特定的演算法快速查詢到某個符合條件的索引,而不是會對索引中每乙個資料都進行一 一的掃瞄判斷,也就是所謂你平常理解的使用索引查詢會更快的取出資料。而要想實現這種查詢,索引卻是有要求的,要實現這種能快速查詢的演算法,索引就要滿足特定的資料結構。簡單說,也就是索引欄位的資料必須是有序的,才能實現這種型別的查詢,才能利用到索引。

有些了解的人可能會問,索引不都是乙個有序排列的資料結構麼。

不過答案說的還不夠完善,那只是針對單個索引,而復合索引的情況有些同學可能就不太了解了。下面就說下復合索引:以該錶的(name,cid)復合索引為例,它內部結構簡單說就是下面這樣排列的:

建立復合索引的規則是首先會對復合索引的最左邊的,也就是第乙個name欄位的資料進行排序,在第乙個欄位的排序基礎上,然後再對後面第二個的cid字段進行排序。其實就相當於實現了類似order by name cid這樣一種排序規則。

所以:第乙個name欄位是絕對有序的,而第二字段就是無序的了。所以通常情況下,直接使用第二個cid字段進行條件判斷是用不到索引的,當然,可能會出現上面的使用index型別的索引。這就是所謂的mysql為什麼要強調最左字首原則的原因。

那麼什麼時候才能用到呢?當然是cid欄位的索引資料也是有序的情況下才能使用咯,什麼時候才是有序的呢?觀察可知,當然是在name欄位是等值匹配的情況下,cid才是有序的。發現沒有,觀察兩個name名字為ccid字段是不是有序的呢。從上往下分別是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查詢優化器會最終以這種順序進行查詢執行。

4、總結

上面的例子是我見過最通俗易懂的答案,總結來說就是:

最左側原則不是要求索引(a,b,c)必須按照where a=x and b=x and c=x 才可以。順序是可以互換的,關鍵是要有這個a,而且這個a一定要是等值匹配。

答:由解釋我們可以知道,如果乙個資料表中的每個欄位都建的有索引,那麼此時不管用哪個字段作為搜尋條件都是可以用到索引的,也就是覆蓋索引了。但是要注意,真正讓你的mysql效能飛起來的還是ref,所以盡量還是按照已有的那些索引規則寫sql吧。

以前總是覺得自己懂了最左側原則的概念,知道怎麼用就好了。實際上呢,還是一堆疑問,始終是知其然不知其所以然。不過這次終於明白的更深了一層。你懂了嗎?

end

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

MySQL深入理解

儲存引擎 innodb表引擎 myisam表引擎 其他的表引擎 索引 索引對效能的影響 索引的使用場景 索引的型別 對比說明 mysql索引的建立原則 mysql索引的注意事項 查詢優化 查詢分析sql查詢慢的原因 優化查詢過程中的資料訪問 避免使用如下sql語句 是否在掃瞄額外的記錄?優化長難的查...

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

最近在看到mysql聯合索引的匹配原則,記錄下自己的理解 一 建立一張表 create table test a int b int,c int,d int,key index abc a,b,c engine innodb default charset utf8 二 插入一些資料進去 drop ...