④ ref
非唯一性索引,对于每个索引键的查询,返回匹配的所有行(可以0,可以1,可以多)
准备数据:
创建索引,并查看执行计划:
# 添加索引 alter table teacher add index index_name (tname) ; # 查看执行计划 explain select * from teacher where tname = 'tz';
结果如下:
⑤ range
检索指定范围的行 ,where后面是一个范围查询(between, >, <, >=, in)
in有时候会失效,从而转为无索引时候的ALL
# 添加索引 alter table teacher add index tid_index (tid) ; # 查看执行计划:以下写了一种等价SQL写法,查看执行计划 explain select t.* from teacher t where t.tid in (1,2) ; explain select t.* from teacher t where t.tid <3 ;
结果如下:
⑥ index
查询全部索引中的数据(扫描整个索引)
⑦ ALL
查询全部源表中的数据(暴力扫描全表)
注意:cid是索引字段,因此查询索引字段,只需要扫描索引表即可。但是tid不是索引字段,查询非索引字段,需要暴力扫描整个源表,会消耗更多的资源。
4)possible_keys和key
possible_keys可能用到的索引。是一种预测,不准。了解一下就好。
key指的是实际使用的索引。
# 先给course表的cname字段,添加一个索引 create index cname_index on course(cname); # 查看执行计划 explain select t.tname ,tc.tcdesc from teacher t,teacherCard tc where t.tcid= tc.tcid and t.tid = (select c.tid from course c where cname = 'sql') ;
结果如下:
有一点需要注意的是:如果possible_key/key是NULL,则说明没用索引。
5)key_len
索引的长度,用于判断复合索引是否被完全使用(a,b,c)。
① 新建一张新表,用于测试
# 创建表 create table test_kl ( name char(20) not null default '' ); # 添加索引 alter table test_kl add index index_name(name) ; # 查看执行计划 explain select * from test_kl where name ='' ;
结果如下:
结果分析:因为我没有设置服务端的字符集,因此默认的字符集使用的是latin1,对于latin1一个字符代表一个字节,因此这列的key_len的长度是20,表示使用了name这个索引。
② 给test_kl表,新增name1列,该列没有设置“not null”
# 新增一个字段name1,name1可以为null alter table test_kl add column name1 char(20) ; # 给name1字段,设置为索引字段 alter table test_kl add index index_name1(name1) ; # 查看执行计划 explain select * from test_kl where name1 ='' ;
结果如下:
结果分析:如果索引字段可以为null,则mysql底层会使用1个字节用于标识。
③ 删除原来的索引name和name1,新增一个复合索引
# 删除原来的索引name和name1 drop index index_name on test_kl ; drop index index_name1 on test_kl ; # 增加一个复合索引 create index name_name1_index on test_kl(name,name1); # 查看执行计划 explain select * from test_kl where name1 = '' ; --121 explain select * from test_kl where name = '' ; --60
结果如下:
结果分析:对于下面这个执行计划,可以看到我们只使用了复合索引的第一个索引字段name,因此key_len是20,这个很清楚。再看上面这个执行计划,我们虽然仅仅在where后面使用了复合索引字段中的name1字段,但是你要使用复合索引的第2个索引字段,会默认使用了复合索引的第1个索引字段name,由于name1可以是null,因此key_len = 20 + 20 + 1 = 41呀!
④ 再次怎加一个name2字段,并为该字段创建一个索引。不同的是:该字段数据类型是varchar
# 新增一个字段name2,name2可以为null alter table test_kl add column name2 varchar(20) ; # 给name2字段,设置为索引字段 alter table test_kl add index name2_index(name2) ; # 查看执行计划 explain select * from test_kl where name2 = '' ;
结果如下:
结果分析:key_len = 20 + 1 + 2,这个20 + 1我们知道,这个2又代表什么呢?原来varchar属于可变长度,在mysql底层中,用2个字节标识可变长度。
6)ref
这里的ref的作用,指明当前表所参照的字段。
注意与type中的ref值区分。在type中,ref只是type类型的一种选项值。
# 给course表的tid字段,添加一个索引 create index tid_index on course(tid); # 查看执行计划 explain select * from course c,teacher t where c.tid = t.tid and t.tname = 'tw';
结果如下:
结果分析:有两个索引,c表的c.tid引用的是t表的tid字段,因此可以看到显示结果为【数据库名.t.tid】,t表的t.name引用的是一个常量"tw",因此可以看到结果显示为const,表示一个常量。
7)rows(这个目前还是有点疑惑)
被索引优化查询的数据个数 (实际通过索引而查询到的数据个数)
explain select * from course c,teacher t where c.tid = t.tid and t.tname = 'tz' ;
结果如下: