Explain的使用和索引解析
explain (extended)
partitions列-是否用了分区
filtered列-半分比的值,rows*fitered/100可以估算出查询行数(了解)
explain extended select * from user where id = 1;
show warnings;
--show warnings;表示note中表示数据库做了什么优化
select_type列
simple:简单查询,不包含子查询和union
primary:复杂查询中最外层的select
subquery:包含在select中的子查询(不再from子句中)
derived:包含在from子句中的子查询,mysql会将结果存放在一个临时表,也称为派生表、隐身表,比如下面的select * from file where id = 1。

deribed3是临时表derived3,其中的3是id中的3。ID越大执行优先级越高,越小执行优先级越低。
type列,关联类型或访问类型,即mysql决定如何查找表中的行,查找数据行记录的大概范围。
效率从优到差:system(系统级查询)>const(常量查询)> eq_ref > ref > range > index > ALL(全表扫描,扫描聚簇索引)
一般来说,得保证查询达到range级别,最好达到ref
为NULL表示:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。在索引层就查到结果,比如select min(id) from users;
system:从某一行指定数据(type为const的结果集中)中查找出来的结果。
select * from (select 1 from actor where id = 1);
const:使用primary key或unique key查询的语句。
select 1 from actor where id = 1;
eq_ref:primary key或unique key索引的所有部分被连接使用,最多只会返回一条符合条件的记录,查询速度也是非常之快。
ref:相比eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。
range:范围扫描,通常出现在in(),between,,>=等操作中,使用一个索引来检索。
index:扫描全索引就能拿到结果,一般是扫描某个二级索引(数据比主键索引的叶子节点的占用内存小(数量是一样的),所以比ALL快一些),这种扫描不会从索引树根节点开始快速查找,而是直接对二级索引的叶子节点遍历和扫描,速度比较慢,这种查询一般未使用覆盖索引。二级索引一般比较小,通常比ALL快一些。
ALL:全表臊面,扫描聚簇索引的所有叶子节点,通常需要增加索引进行优化了。全部扫描聚簇索引(叶子节点)由左到右获取结果,而不是从树根节点由上而下查询。
index和ALL对比:
| 特性 | type: index(全索引扫描) | type: ALL(全表扫描) |
| 扫描目标 | 索引树 | 硬盘上的实际数据行 |
| 数据有序性 | 按索引顺序读取,天然有序 | 无序读取,顺序由物理存储决定 |
| 数据量 | 通常只读取索引数据,数据量小 | 读取整行数据(包括所有列),数据量大 |
| 典型场景 | SELECT查询的字段全部是索引列(覆盖索引) | SELECT *或查询条件无索引可用 |
| 是否利用索引 | 是,但扫描的是整个索引 | 否,完全未使用索引 |
possible_keys列,查询时可能用到的索引。
key列,查询时真正用到的索引。
如果查找的结果集,在主键索引和辅助索引中都有的话,mysql优先会选用辅助索引(占用空间小)。如果在辅助索引中不全有,就会选择主键索引。mysql会在查询之前计算每个查询的成本,使用最小成本查询。(mysql怎么选索引?)
key_len列:使用到的索引的字节长度,联合索引中可能存在多个字段,若使用了多个字段,就是字段长度之和。有计算规则(了解)。
rows列:预估查询结果行数。
Extra列:额外信息。
Using index:使用覆盖索引(通过索引就能查到结果集,不需要回表查询,就是覆盖索引),但它并不是索引,而是查询方式。一般针对的是辅助(二级)索引,只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其他字段值。使用了索引树(二级索引),空间小,读取快,读取ibd文件到内存中。
比如查询distinct name,name是复合索引中首个字段,在下面索引中就可以将重复值去除。

Using where:服务器层在存储引擎返回行后,使用where语句来过滤结果,并且查询的列未被索引覆盖,最好通过优化索引在存储引擎层完成过滤。
Using index condition:使用了索引条件下推,查询的列不完全被索引覆盖,还需要回表查询,where条件中是一个前导列的范围。
Using temporary:mysql需要创建一张临时表来处理查询,需要优化了。因为查询字段不在索引中,需要将结果集放在内存中进行优化。
Using filesort:order by时的Extra,将用外部排序(当需要排序的数据量太大,无法全部放入sort_buffer时,MySQL就会使用临时文件来辅助排序。这个过程就是所谓的“外部排序”。分治策略:1.分块排序:将数据分成多个小块,每个块在sort_buffer内排好序后,写入一个临时文件。2.归并排序:当所有数据块都处理完毕后,MySQL会使用归并排序算法,将这些已经有序的临时文件合并成一个最终有序的大文件作为结果集。)而不是索引排序,数据较小时从内存排序,否则需要在磁盘完成排序。这种情况就需要使用索引优化了。读取聚簇索引,占用空间大,所以慢,使用了内存的sort buffer。
Select tables optimized away:使用某些聚合函数(max,min)来访问存在索引中的某个字段,无需访问数据行。效率高。
组合索引 key 'idx_name_age_position' (name,age,position) using btree;
EXPLAIN select * from employees where name = 'LiLei' and age = 22 and position = 'manager'; EXPLAIN select * from employees where name = 'LiLei' and age > 22 and position = 'manager';
从key_len来看,第一个使用了三个字段作为索引 (key_len=140),第二个只使用了前两个字段作为索引(key_len=78)。
原因:叶子节点在name和age相同,position不同时,使用position保证数据的有序性,如果只有name相等,age和position不同,就会使用age来保证数据的有序性,这时的position就无法被保证有序,所以position字段没有被使用到索引中去。
这种情况不但遵循了最左前缀,第二左前缀也会遵守。
优化方案:
mysql在使用不等于的时候无法使用索引,会导致全表扫描。但不绝对。
is null,is not null一般情况下也无法使用索引。
like 以通配符开头('$abc...'),mysql索引失效会变成全表扫描操作。但是查询结果中的字段如果都在索引中,也可以使用到覆盖索引(type=index)。
字符串不加单引号索引失效
少用or或者in,用它查询时,mysql不一定使用索引,优化器会根据检索比例,表大小等多个因素整体评估是否使用索引。
范围查询优化,可能会因为查询范围太大,导致优化后采用不使用索引方案。
explain select * from employees where age >= 1 and age <= 2000;--possible_keys有值,但key为空。explain select * from employees where age >= 1000 and age <= 2000;--possible_keys有值,key也有值,且为相同索引
覆盖索引:
即使用索引即可以覆盖结果集的查询叫做覆盖索引。覆盖索引就像一个“超级目录”,一般是创建了复合索引,它不仅告诉你所需内容在哪一页,还直接把内容展示给你,让你无需翻到具体页面就能获得答案。在覆盖索引树中找到所有符合条件的记录,无需回表,所有数据已全部在辅助索引的叶子节点中,直接从索引中返回所需要的数据。Extra显示Using index时,表示查询成功使用了覆盖索引。







