从一道有趣的题目开始分析:

 

假设某个表有一个联合索引(id,name,age)以下选项哪些字段使用了该索引:

A where id=? and name=? and age>? 

B where  id=? and name=? order by age

C where   id=? and age=? group by name

D where   name=? and id=?

E where   name=? and  age=? AND id=?

F where   name=? and  age=?

 

G GROUP BY id,name 

H GROUP BY name,id

 

 

首先创建表:

 

CREATE TABLE `test` (

  `id` int(10) unsigned NOT NULL,

  `name` varchar(10) NOT NULL,

  `age` smallint(3) unsigned NOT NULL,

  KEY `union_index` (`id`,`name`,`age`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

说明:

MySQL explain中key_len的计算

key_len表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在组合索引的时候,判断该索引有多少部分被使用到非常重要。
在计算key_len时,下面是一些需要考虑的点:

索引字段的附加信息:可以分为变长和定长数据类型讨论,当索引字段为定长数据类型时,如char,int,datetime,需要有是否为空的标记,这个标记占用1个字节(对于not null的字段来说,则不需要这1字节);对于变长数据类型,比如varchar,除了是否为空的标记外,还需要有长度信息,需要占用两个字节。

 

对于,char、varchar、blob、text等字符集来说,key len的长度还和字符集有关,latin1一个字符占用1个字节,gbk一个字符占用2个字节,utf8一个字符占用3个字节。

综上,下面来看一些例子:

列类型 KEY_LEN 备注
id int key_len = 4+1 int为4bytes,允许为NULL,加1byte
id bigint not null key_len=8 bigint为8bytes
user char(30) utf8 key_len=30*3+1 utf8每个字符为3bytes,允许为NULL,加1byte
user varchar(30) not null utf8 key_len=30*3+2 utf8每个字符为3bytes,变长数据类型,加2bytes
user varchar(30) utf8 key_len=30*3+2+1 utf8每个字符为3bytes,允许为NULL,加1byte,变长数据类型,加2bytes
detail text(10) utf8 key_len=30*3+2+1 TEXT截取部分,被视为动态列类型。

备注:key_len只指示了where中用于条件过滤时被选中的索引列,是不包含order by/group by这一部分被选中的索引列的。

 

写入6条数据

mysql联合索引的使用

 

论证 A where id=? and name=? and age>? 

 

mysql联合索引的使用

 

分析:

type:range, 一个范围内查找

key:union_index,使用了联合索引

key_len: id(int NOT NULL) 4

              name(varchar 10 NOT NULL utf8)  3*10+2

              age (smallint NOT NULL ) 2

              索引总长度:4+32+2 = 38

结论:id,name,age上的索引都使用了

 

论证 B where  id=? and name=? order by age

mysql联合索引的使用

 

分析:

 

type:ref, 使用了索引查找

key:union_index,使用了联合索引

key_len: id(int NOT NULL) 4

              name(varchar 10 NOT NULL utf8)  3*10+2

              索引总长度:4+32 = 36

extra:没有出现Using filesort

结论:id,name上的索引都使用了,order by上没有使用索引

 

论证  C where  id=? and age=? group by name

mysql联合索引的使用

 

分析:

 

type:ref, 使用了索引查找

key:union_index,使用了联合索引

key_len: id(int NOT NULL) 4

              索引总长度:4

extra:没有出现Using index for group-by

结论:id上的索引使用了,group by上没有使用索引

 

论证  D where   name=? and id=?

mysql联合索引的使用

 

分析:

 

type:ref, 使用了索引查找

key:union_index,使用了联合索引

key_len: id(int NOT NULL) 4

              name(varchar 10 NOT NULL utf8)  3*10+2

              索引总长度:4+32 = 36

结论:id,name上的索引都使用了

 

论证  E where  name=? and  age=? AND id=?

mysql联合索引的使用

 

分析:

type:ref, 使用了索引查找

key:union_index,使用了联合索引

key_len: id(int NOT NULL) 4

              name(varchar 10 NOT NULL utf8)  3*10+2

              age (smallint NOT NULL ) 2

              索引总长度:4+32+2 = 38

结论:id,name,age上的索引都使用了

 

论证  F where  name=? and  age=? 

mysql联合索引的使用

 

分析:

prossible_keys:null, 说明没有任何索引会被用

rows:6,做了全表扫描

结论:无索引会被使用

 

论证 G GROUP BY id,name 

        H GROUP BY name,id

mysql联合索引的使用

mysql联合索引的使用

分析:

使用group by 一般先生成临时文件,再进行排序,但是字段顺序为id,name时,并没有用临时表进行排序,而是利用索引排序好的;当group by字段为name,id时,由于与索引字段顺序不一致,所以分组没有利用到索引,排序用了默认的索引排序

 

总结:

索引的最左原则(左前缀原则),如(id,name,age)的联合索引,可理解为建立了(id),(id,name), (id,name,age)索引。where 条件按照索引建立的字段顺序来使用(不代表and条件必须按照顺序来写),如果中间某列没有条件,后面的列不能使用索引(如F)。

 

索引也能用于分组和排序,分组要先排序。所以在分组和排序中,如果字段顺序可以按照索引的字段顺序,即可利用索引的有序特性。

 

mysql联合索引的使用

 

观注快乐程序员公众号,每日分享一点小知识。爱编程,爱生活!

相关文章: