Mysql索引失效原理與最左匹配原則

索引的底層是一顆B+樹,那麼聯合索引當然還是一顆B+樹,只不過聯合索引的健值數量不是一個,而是多個。構建一顆B+樹只能根據一個值來構建,因此數據庫依據聯合索引最左的字段來構建B+樹。
例子:假如創建一個(a,b)的聯合索引,那麼它的索引樹是這樣的
在這裏插入圖片描述

可以看到a的值是有順序的,1,1,2,2,3,3,而b的值是沒有順序的1,2,1,4,1,2。所以b = 2這種查詢條件沒有辦法利用索引,因爲聯合索引首先是按a排序的,b是無序的。

同時我們還可以發現在a值相等的情況下,b值又是按順序排列的,但是這種順序是相對的。所以最左匹配原則遇上範圍查詢就會停止,剩下的字段都無法使用索引。例如a = 1 and b = 2 a,b字段都可以使用索引,因爲在a值確定的情況下b是相對有序的,而a>1and b=2,a字段可以匹配上索引,但b值不可以,因爲a的值是一個範圍,在這個範圍中b是無序的。

最左匹配原則:最左優先,以最左邊的爲起點任何連續的索引都能匹配上。同時遇到範圍查詢(>、<、between、like)就會停止匹配。

假如建立聯合索引(a,b,c)

1 全值匹配查詢時

select * from table_name where a = '1' and b = '2' and c = '3' 
select * from table_name where b = '2' and a = '1' and c = '3' 
select * from table_name where c = '3' and b = '2' and a = '1' 
......

用到了索引

where子句幾個搜索條件順序調換不影響查詢結果,因爲Mysql中有查詢優化器,會自動優化查詢順序

2 匹配左邊的列時

select * from table_name where a = '1' 
select * from table_name where a = '1' and b = '2'  
select * from table_name where a = '1' and b = '2' and c = '3'

都從最左邊開始連續匹配,用到了索引

select * from table_name where  b = '2' 
select * from table_name where  c = '3'
select * from table_name where  b = '1' and c = '3' 

這些沒有從最左邊開始,最後查詢沒有用到索引,用的是全表掃描

select * from table_name where a = '1' and c = '3' 

如果不連續時,只用到了a列的索引,b列和c列都沒有用到

3 匹配列前綴

如果列是字符型的話它的比較規則是先比較字符串的第一個字符,第一個字符小的哪個字符串就比較小,如果兩個字符串第一個字符相通,那就再比較第二個字符,第二個字符比較小的那個字符串就比較小,依次類推,比較字符串。

如果a是字符類型,那麼前綴匹配用的是索引,後綴和中綴只能全表掃描了

select * from table_name where a like 'As%'; //前綴都是排好序的,走索引查詢
select * from table_name where  a like '%As'//全表查詢
select * from table_name where  a like '%As%'//全表查詢

4 匹配範圍值

select * from table_name where  a > 1 and a < 3

可以對最左邊的列進行範圍查詢

select * from table_name where  a > 1 and a < 3 and b > 1;

多個列同時進行範圍查找時,只有對索引最左邊的那個列進行範圍查找纔用到B+樹索引,也就是隻有a用到索引,在1<a<3的範圍內b是無序的,不能用索引,找到1<a<3的記錄後,只能根據條件 b > 1繼續逐條過濾

5 精確匹配某一列並範圍匹配另外一列

如果左邊的列是精確查找的,右邊的列可以進行範圍查找

select * from table_name where  a = 1 and b > 3;

a=1的情況下b是有序的,進行範圍查找走的是聯合索引

6 排序

一般情況下,我們只能把記錄加載到內存中,再用一些排序算法,比如快速排序,歸併排序等在內存中對這些記錄進行排序,有時候查詢的結果集太大不能在內存中進行排序的話,還可能暫時藉助磁盤空間存放中間結果,排序操作完成後再把排好序的結果返回客戶端。Mysql中把這種再內存中或磁盤上進行排序的方式統稱爲文件排序。文件排序非常慢,但如果order子句用到了索引列,就有可能省去文件排序的步驟

select * from table_name order by a,b,c limit 10;

因爲b+樹索引本身就是按照上述規則排序的,所以可以直接從索引中提取數據,然後進行回表操作取出該索引中不包含的列就好了

order by的子句後面的順序也必須按照索引列的順序給出,比如

select * from table_name order by b,c,a limit 10;

這種顛倒順序的沒有用到索引

select * from table_name order by a limit 10;
select * from table_name order by a,b limit 10;

這種用到部分索引

select * from table_name where a =1 order by b,c limit 10;

聯合索引左邊列爲常量,後邊的列排序可以用到索引

原文鏈接:https://blog.csdn.net/sinat_41917109/article/details/88944290

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章