分享主题
mysql explain查询计划
分享目标
- 掌握最左前缀原则
- 掌握explain查询计划显示索引是否被使用到
- 掌握如何正确使用索引,才不会引起索引失效
查看执行计划
介绍
MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句的执行计划进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化.使用explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。可以通过explain命令深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。
EXPLAIN 命令用法十分简单, 在 SELECT 语句前加上 explain 就可以了, 例如:
参数说明
expain出来的信息有10列,分别是
1 | id: SELECT查询的标识符,每个SELECT都会自动分配一个唯一的标识符 |
建表语句
新建user表, 添加组合索引idx_name_age和单列索引idx_sex,案例mysql版本是5.7版本;
1 | CREATE TABLE `user` ( |
1 | INSERT INTO `user` (`id`, `name`, `age`, `sex`, `address`) VALUES ('1', 'zhangsan', '20', '0', '中信广场'); |
select_type(重要)
查询类型,主要用于区别普通查询、联合查询(union、union all)、子查询等复杂查询。
simple: 简单SELECT(不使用UNION或子查询)
1 | mysql> explain select *from user; |
primary:最外面的SELECT
1 | mysql> explain select(select name from user) from user; |
subquery:除了from字句中包含的子查询外,其他地方出现的子查询都可能是subquery
1 | mysql> explain select *from user where id=(select max(id) from user); |
type(重要)
1 | 依次从好到差: |
除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一个索引,最少要索引使用到range级别
system
1 | 表中只有一行数据或者是空表 |
1 | mysql> explain select *from (select *from user where id=1) a; |
const(重要)
1 | 使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。其他数据库也叫做唯一索引扫描 |
1 | mysql> explain select *from user where id=1; |
eq_ref(重要)
1 | 连接字段主键或者唯一性索引。 |
1 | mysql> explain select a.id from user a left join user b on a.id=b.id; |
ref(重要)
1 | 针对非唯一性索引,使用等值(=)查询非主键。或者是使用了最左前缀规则索引的查询。 |
1 | --非唯一索引 |
range(重要)
1 | 索引范围扫描,常见于使用>,<,is null,between ,in ,like等运算符的查询中。 |
1 | mysql> explain select * from user where id >1; |
all(重要)
1 | 这个就是全表扫描数据文件,然后再在**server**层进行过滤返回符合要求的记录。 |
1 | mysql> explain select * from user; |
extra(重要)
1 | 这个列包含不适合在其他列中显示单十分重要的额外的信息,这个列可以显示的信息非常多,有几十种,常用的有 |
using filesort
1 | mysql> explain select * from user order by address; |
using index(重要)
1 | 表示相应的SELECT查询中使用到了覆盖索引(Covering Index),避免访问表的数据行,效率不错 |
1 | --全值匹配 覆盖索引 |
using where(重要)
1 | 查询条件中分为限制条件和检查条件,5.6之前,存储引擎只能根据限制条件扫描数据并返回,然后server层根 |
1 | --无索引查询 |
索引失效分析
1 | 1.全值匹配我最爱 |
全值匹配我最爱
1 | mysql> explain select * from user where name='zhangsan' and age=20; |
最佳左前缀法则
1 | 组合索引,带头索引不能死,中间索引不能断 |
1 | --错误示例 |
不要在索引上做计算
1 | 不要进行这些操作:计算、函数、自动/手动类型转换,不然会导致索引失效而转向全表扫描 |
1 | mysql> explain select * from user where name='zhangsan'; |
范围条件右边的列失效
1 | 不能继续使用索引中范围条件(bettween、<、>、in等)右边的列 |
1 | mysql> explain select * from user where name='zhangsan' and age>20; |
尽量使用覆盖索引
1 | 尽量使用覆盖索引(只查询索引的列),也就是索引列和查询列一致,减少select * |
1 | mysql> explain select * from user; |
索引字段上不要使用不等
1 | 索引字段上使用(!= 或者 < >)判断时,会导致索引失效而转向全表扫描 |
1 | mysql> explain select * from user where name!='zhangsan'; |
主键索引字段上不可以判断null
1 | 主键字段上不可以使用 null |
1 | --非主键索引 |
索引字段使用like不以通配符开头
1 | 索引字段使用like以通配符开头(‘%字符串’)时,会导致索引失效而转向全表扫描 |
1 | mysql> explain select * from user where name like '%san'; |
索引字段字符串要加单引号
1 | 索引字段是字符串,但查询时不加单引号,会导致索引失效而转向全表扫描 |
1 | mysql> explain select * from user where name=123; |
索引字段不要使用or
1 | 索引使用or会导致索引失效,全表扫描 |
1 | mysql> explain select * from user where name='zhangsan' or age=20; |
总结
1 | 全值匹配我最爱,最左前缀要遵守 |
[参考链接]