一群DBA朋友聊天,突然抛出一个某公司联合索引的面试题,当时好多人都蒙了,这次针对这个问题,做了个简单的实验,把联合索引的作用一次搞清楚
问题大概是这样的,联合索引(a,b,c,d)下面这类的查询分别用到联合索引的哪部分?
select * from t where a=1 and b=1 and d>1 and c=1;
select * from t where a=1 and b>1 and c>1 order by b,c;
select * from t where a=1 and b=1 and c=1 and d=1 order by b;
select * from t where a=1 and b>1 and d=1 order by c;
下面建立测试表,字段都用int not null,并插入测试数据
CREATE TABLE `NewTable` (
`id` int NOT NULL ,
`a` int NOT NULL ,
`b` int NOT NULL ,
`c` int NOT NULL ,
`d` int NOT NULL ,
PRIMARY KEY (`id`)
)
;
建立联合索引
ALTER TABLE `t`
ADD INDEX `idx_a_b_c_d` (`a`, `b`, `c`, `d`) ;
1.explain select * from t where a=1 and b=1 and d>1 and c=1\G;
id: 1
select_type: SIMPLE
table: t
type: range
possible_keys: idx_a_b_c_d
key: idx_a_b_c_d
key_len: 16
ref: NULL
rows: 1
Extra: Using where; Using index
key_len=16说明索引走了4个字段 4*4字节,联合索引用到全部字段
2.explain select * from t where a=1 and b>1 and c>1 order by b,c\G;
id: 1
select_type: SIMPLE
table: t
type: range
possible_keys: idx_a_b_c_d
key: idx_a_b_c_d
key_len: 8
ref: NULL
rows: 1
Extra: Using where; Using index
key_len=8 说明where过滤用了两个字段 ab, Extra没有file sort,说明排序用到全部索引bc,所以这个查询用到了索引的abc部分
3.explain select * from t where a=1 and b=1 and c=1 and d=1 order by b\G;
id: 1
select_type: SIMPLE
table: t
type: ref
possible_keys: idx_a_b_c_d
key: idx_a_b_c_d
key_len: 16
ref: const,const,const,const
rows: 3
Extra: Using index
key_len=16 说明where过滤用了4个字段abcd,Extra没出现file sort,说明排序用到了索引b。
4.explain select * from t where a=1 and b>1 and d=1 order by c\G;
id: 1
select_type: SIMPLE
table: t
type: range
possible_keys: idx_a_b_c_d
key: idx_a_b_c_d
key_len: 8
ref: NULL
rows: 1
Extra: Using where; Using index; Using filesort
key_len=8说明where过滤用到了两个字段ab, Extra出现filesort,说明排序字段没用到索引
这类的查询就不一一测试了,总结一下看这类执行计划应该注意的点
key_len
1)key_len单位是字节,比如int,一个字段是4,两个字段是8
(如果字段可以为空,那么key_len会+1,也就是int会显示5,两个字段显示10)
2)key_len显示的是where条件用到索引长度,order by 和group by之后的字段不显示在key_len里面
Extra
两种情况会出现file sort
1)where 条件后面没有这个字段,但是order by这个字段,会出现file sort
2)order by的字段没走索引,会出现file sort
还有比较重要的是,联合索引遇到范围查询会停止继续检索,比如where a=1 and b=1 and c>1 and d=1那么索引只会检索到abc
当然,排序会延续使用where条件后面的索引,比如下面的情况
mysql> explain select * from t where a=1 and b>1 order by b,c\G ;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
type: range
possible_keys: idx_a_b_c_d
key: idx_a_b_c_d
key_len: 8
ref: NULL
rows: 1
Extra: Using where; Using index
排序用到了ab,但是排序用到了bcd,也就是这整条查询用到了abcd全部联合索引