项目开发中,性能是我们比较关注的问题,特别是数据库的性能;作为一个开发,经常和SQL语句打交道,想要写出合格的SQL语句,我们需要了解SQL语句在数据库中是如何扫描表、如何使用索引的;
MySQL提供explain/desc命令输出执行计划,我们通过执行计划优化SQL语句。
下面我们以MySQL5.7为例了解一下执行计划:
注:文中涉及到的表结构、sql语句只是为了理解explain/desc执行计划,有不合理之处勿喷
explain/desc 用法
只需要在我们的查询语句前加 explain/desc即可
准备数据表
1 --创建user表
2 create table user(3 id int,4 name varchar(20),5 role_id int,6 primary key(id)7 )engine=innodb default charset=utf8;8 --创建role表
9 create tablerole(10 id int,11 name varchar(20),12 primary key(id)13 )engine=innodb default charset=utf8;
查询,执行计划
1 explain select * from user;
执行计划输出有id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、extra,这些内容有什么意义,下面简单介绍一下
explain/desc 输出详解
一、id ,select 查询序列号
1 id相同,从上往下一次执行;
1 --左关联
2 explain select * from user a left join user b on a.id=b.id;3 --右关联
4 explain select * from user a right join user b on a.id=b.id;
通过left join 和 right join 验证;id一样(注意执行计划的table列),left join 先扫描a表,再扫描b表;right join 先扫描b表,再扫描a表
2 id不同,id越大优先级越高,越先被执行
1 desc select * from user where role_id=(select id from role where name='开发');
我们编写查询角色为开发的用户;可以知道先查询角色name为开发角色id,查询序列号为2;再根据角色id查询用户,查询序列号为1;
二、select_type,查询语句类型
(1) SIMPLE(简单SELECT,不使用UNION或子查询等)
1 explain select * from user;
(2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)
1 desc select * from user where role_id=(select id from role where name='开发');
(3) UNION(UNION中的第二个或后面的SELECT语句)
1 desc select * from user where name='Java' union select * from user where role_id=1;
(4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)
1 desc select * from usera2 where id in(3 select b.id from user b where b.id=a.id union
4 select c.id from role c where c.id=a.role_id5 );
(5) UNION RESULT(UNION的结果)
1 desc select * from user where name='Java' union select * from user where role_id=1;
(6) SUBQUERY(子查询中的第一个SELECT)
1 desc select * from user where role_id=(select id from role where name='开发');
(7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)
1 desc select * from user where role_id = ( select id from role where id=user.id );
(8) DERIVED(派生/衍生表的SELECT, FROM子句的子查询)
1 desc select * from ( select * from user where name='Java' union select * from user where role_id=1 ) a;