示例數據
-- 創建表 create table table1( col1 int primary key, col2 int, col3 int, col4 int, col5 varchar(20) ) engine=INNODB; -- 插入數據 insert into table1 values(4, 3, 1, 1, 'd'); insert into table1 values(1, 1, 1, 1, 'a'); insert into table1 values(8, 8, 8, 8, 'h'); insert into table1 values(2, 2, 2, 2, 'b'); insert into table1 values(5, 2, 3, 5, 'e'); insert into table1 values(3, 3, 2, 2, 'c'); insert into table1 values(7, 4, 5, 5, 'g'); insert into table1 values(6, 6, 4, 4, 'f'); -- 添加組合索引 alter table table1 add index idx_table1_col234(col2, col3, col4);
查詢SQL:select * from table1; 默認按主鍵從小到大排序,如下圖所示

組合索引原理
組合索引排序規則:先比較第一個列值的大小進行排序,如果相同,再比較第二列值的大小進行排序,如果再相同,再比較第三列值的大小...依次進行排序。
組合索引(沒有主鍵索引的情況)如下圖所示:

如圖所示

說明:111,表示col2,col3,col4的組合值,藍色表示主鍵
假設:
- select * from table1 where col2 =2 and col3 =2 and col4 = 5;相當於查詢索引值 = 225;
- select * from table1 where col2 =2 and col3 =2;相當於查詢索引值 = 22*;
- select * from table1 where col2 =2;相當於查詢索引值 = 2**;
假設:
- select * from table1 where col3 =2 and col4 = 5; 即相當於查詢”索引值“ = *25,無法確定其值的大小。索引失效
(1)為什么范圍后面的索引全失效?
組合索引中未遵循最左例原則的情況下,索引失效,這個好理解,但是當最左列為范圍查找時,后面那些列的索引不會用到,為什么?
(2)為什么有時候明明用了索引而不走索引?
select col2, col5 from table1 where col2 > 3; -- 走索引 select col2 from table1;-- 走索引 select col2 from table1 where col2 > 1; -- 走索引 select col2, col5 from table1 where col2 > 1; -- 不走索引 select col1, col2 from table1 where col2 > 1; -- 走索引
原因:
當執行查詢select col2, col5 from table1 where col2 > 1 時,查詢出來一共會有7條記錄(總記錄8條),因為非聚簇索引,索引與數據是分開的,因此每查詢出來一條數據都要回表查詢一次,這里共要回表7次;即走索引時,需要回表查詢7次,7次IO,而全表掃描時4次,4次IO,mysql優化器自動幫你選擇了走全表掃描。
當執行查詢select col1, col2 from table1 where col2 > 1 時,因為col1屬於主鍵索引,並且數據保存在該組合索引的節點上,因此不需要回表查詢,也就走索引。
(3)發生類型轉換時不走索引的原因
select * from table1 where col1 = 'a'; -- 不走索引,字符a會默認轉換為數字0(所有字符都會轉換為0) select * from table1 where col5 = 1; -- 不走索引,mysql會將col5列所有字段全部轉換為int類型,因此為不走索引,全表掃描; 同理 select * from table1 where col1 + 1 = 5;--也不會走索引,mysql會將 col1列所有字段全部+1操作,所有列全部操作一次,就相當於進行了一次全表掃描