索引的底層是一顆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