explain 续

possible_keys key

possible_keys:

显示可能用在表中的索引 一个或者多个

查询涉及到的字段上若存在多个索引,则该索引将会被列出(但不一定被实际查询使用)

key:

实际使用的索引 如果为null 则表示没有使用索引

若查询中出现覆盖索引,则该索引仅出现在key列表中

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_index_age` (`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', '测试', '18');
INSERT INTO `user` VALUES ('3', '测试', '18');
INSERT INTO `user` VALUES ('4', '测试', '18');
INSERT INTO `user` VALUES ('5', '测试', '18');
INSERT INTO `user` VALUES ('6', '测试', '18');

执行1:

explain select  id   from user where id  = 5

结果1:

MySQL 续集 04_数据

可能用到PRIMARY 实际用到PRIMARY

执行2:

explain select  age,id   from user where id  = 5  and age = 18

结果2:

MySQL 续集 04_数据_02

可能用到PRIMARY,user_index_age 结果用到 PRIMARY

执行3:

explain select  age  from user where id  in (1,2,3,4,5)

结果3:

MySQL 续集 04_数据_03

可能用到 PRIMARY 结果却用到了user_index_age

覆盖索引:

-- 创建表 test 
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`sex` int(1) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `test_index_age_name` (`age`,`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

执行:

explain select name ,age  from test  
explain select name from test
explain select age from test

MySQL 续集 04_st表_04

MySQL 续集 04_字段_05

MySQL 续集 04_st表_06

这个就是覆盖索引:



解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。上边例子中age name 联合索引 如果只查询age 或者只查询name 或者查询age name 都会被覆盖



解释二: 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。



解释三:是非聚集组合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆盖查询语句[select子句]与查询条件[Where子句]中所涉及的字段,也即,索引包含了查询正在查找的所有数据)。
比如上边换成以下语句是不能用到覆盖索引的 id不在索引中 不能被覆盖:

explain select  age  from test  where id = ''


注意:不是所有类型的索引都可以成为覆盖索引。覆盖索引必须要存储索引的列,而哈希索引、空间索引和全文索引等都不存储索引列的值,所以MySQL只能使用B-Tree索引做覆盖索引 可以换一下索引类型试试 确实不行



key_len:


  • 表示索引中使用的字节数,可通过该列计算查询中使用到索引的长度,在不损失精度的情况下(这里的精度指的是查询结果的精确度 比如where中条件多 结果就更精确) 长度越短越好
  • key_len 显示的值为索引的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得出的结果,不是通过表内检索出的
    还是上边的test表:
    执行1:

explain select sex from test  where name ='测试'

结果1:

MySQL 续集 04_st表_07

key_len = 768

执行2:

explain select sex from test  where name ='测试' and age =18

结果2:

MySQL 续集 04_st表_08

key_len变成了 773了 因为查询条件加了个age 更加精确了

ref:

DROP TABLE IF EXISTS `test1`;
CREATE TABLE `test1` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

test表与test1表

执行:

explain select *  from test  ,test1 where test.id= test1.id and test.name = '测试'

在这里插入图片描述

​test.name​​ = ‘测试’ =》 ref = const 是一个常量条件

test.id= ​​test1.id​​ 用到了test数据库中的test1表的id 字段 ​​test.test1.id​

rows:

根据表统计信息及索引选用情况,大致估算出找到所需的记录需要读取的行数(当然越小越好啦)

test表的索引先删除 创建几百条数据

explain select age  from test where age =12 and name ='测试'

MySQL 续集 04_st表_09

可以看到 这里读取了2048行

把索引加上:

ALTER TABLE `test`
DROP INDEX `test_index_name_age` ,
ADD INDEX `test_index_name_age` (`age`, `name`) USING BTREE ;

再执行:

explain select age  from test where age =12 and name ='测试'

MySQL 续集 04_数据_10

这里读取一行就把数据读去出来了 厉害了!! 因为age字段有索引 它就会判断 一下子就知道没有12这个值得age 所以就直接出结果

Extra:

包含不适合在其他列显示的但是十分重要额外信息

  1. Using filesort 遇到后 性能受影响
    说明mysql会对数据使用外部索引排序,而不是按照表内的索引顺序进行读取,也就是说MYSQL无法利用索引完成的排序操作称之为“文件排序”
    还是用test表
explain select  id from test   order  by   name

MySQL 续集 04_数据_11

MySQL 续集 04_数据_12

这里看到了 我们创建的索引顺序是age,name

但是这里直接是order by name 相当于age是一楼 name是二楼 你直接跳过一楼上二楼 那就不合适了 就会产生内排序!

再执行:

explain select  id from test   order  by   age,name

MySQL 续集 04_字段_13

后者性能 高于前者 按照age name(索引顺序) 进行排序 ,出现前者问题 如果有可能 需要尽快优化

  1. using temporary 这个性能更差了!
    使用了临时表保存中间结果,MYSQL在查询排序时使用临时表,常用语排序order by 和 分组查询 group by
explain select  id from test   group    by   name

MySQL 续集 04_字段_14

explain select  id from test   group    by age,  name

MySQL 续集 04_字段_15

这个与上边的order by意思差不多 就是我们索引顺序是age name 但是如果group by name 就是跳过了age 所以出现了使用临时表(伤性能) 所以最好group by 按照index的顺序来 group by age,name

  1. using index 中奖了!
    表示相应的操作使用了覆盖索引,避免访问了表的数据行,效率不错
    如果同时出现using where 表明索引被用来执行键值查找

第一种:

explain select  age  from test  where  name ='测试'

MySQL 续集 04_st表_16

第二种:

explain select  age  name from test

MySQL 续集 04_st表_17

using index 直接从索引读取数据 没有进行查找动作



using where 使用了where



using join buffer 使用了连接缓存 join join 多了 就会有缓存 这个最大值可以调



impossible where
where 值总是false 不能用来获取任何元组
MySQL 续集 04_字段_18



或者

explain select  age  name from test    where name ='2' and name ='3'
  1. select tables optimized away

没有group by 子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM 存储引擎优化count(*) 操作 , 不必等到执行阶段再进行计算,查询执行计划生成阶段即完成优化

MySQL 续集 04_数据_19

  1. distinct
    使用了distinct