能写sql 只是程序员的基本功,能写出性能优异的SQL是优秀程序员的必备技能
要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有简单的了解。
MySQL本身的功能架构分为三个部分,分别是 应用层、逻辑层、物理层,不只是MySQL ,其他大多数数据库产品都是按这种架构来进行划分的。
应用层,主要负责与客户端进行交互,建立链接,记住链接状态,返回数据,响应请求,这一层是和客户端打交道的。
逻辑层,主要负责查询处理、事务管理等其他数据库功能处理,以查询为例。
物理层,实际物理磁盘上存储的文件,主要分为数据文件,日志文件
通过上面的描述,生成执行计划是执行一条SQL必不可少的步骤,一条SQL性能的好坏,可以通过查看执行计划很直观的看出来,执行计划提供了各种查询类型与级别,方面我们进行查看以及为作为性能分析的依据。
所谓的执行计划,就是mysql如何执行一条Sql语句,包括sql查询的顺序、是否使用索引、以及使用索引信息的等等。
MySQL为我们提供了 explain 关键字来直观的查看一条SQL的执行计划。
//1. 查询table_name
select * from table_name where name="explain";
//2. 查看上述语句的执行计划
explain select * from table_name where name="explain";
执行查看上述2语句后,我们可以得出以下执行计划结果
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | table_name | ALL | 1 | Using where |
上面这个执行计划给到的信息是: 这个结果通过一个简单的语句全表扫描,共扫描1行,使用where条件在t_base_user表中筛选出的。
要想看懂执行计划,就要明白每一个参数的含义
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra |
---|
有一组数字组成。表示一个查询中各个子查询的执行顺序;
每个子查询的查询类型,一些常见的查询类型。
id | select_type | description |
---|---|---|
1 | SIMPLE | 不包含任何子查询或union等查询 |
2 | PRIMARY | 包含子查询最外层查询就显示为 PRIMARY |
3 | SUBQUERY | 在select或 where字句中包含的查询 |
4 | DERIVED | from字句中包含的查询 |
5 | UNION | 出现在union后的查询语句中 |
6 | UNION RESULT | 从UNION中获取结果集,例如上文的第三个例子 |
表示该语句查询的表
表分区、表创建的时候可以指定通过那个列进行表分区。 ex:
create table tmp (
id int unsigned not null AUTO_INCREMENT,
name varchar(255),
PRIMARY KEY (id)
) engine = innodb
partition by key (id) partitions 5;
访问类型
ALL
扫描全表数据index
遍历索引range
索引范围查找index_subquery
在子查询中使用 refunique_subquery
在子查询中使用 eq_refref_or_null
对Null进行索引的优化的 reffulltext
使用全文索引ref
使用非唯一索引查找数据eq_ref
在join
查询中使用RIMARY KEY
or UNIQUE NOT NULL
索引关联。const
使用主键或者唯一索引,且匹配的结果只有一条记录。system const
连接类型的特例,查询的表为系统表。查询涉及到的字段上若存在索引,则该索引将被列出来。当该列为 NULL时就要考虑当前的SQL是否需要优化了。可能使用的索引,注意不一定会使用。
显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。
Tips:
查询中若使用了覆盖索引(覆盖索引:索引的数据覆盖了需要查询的所有数据),则该索引仅出现在key列表中
索引长度 char()、varchar()索引长度的计算公式:
(Character Set:utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列长度 + 1(允许null) + 2(变长列)
其他类型索引长度的计算公式: ex:
CREATE TABLE `student` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL DEFAULT '',
`age` int(11),
PRIMARY KEY (`id`),
UNIQUE KEY `idx` (`name`),
KEY `idx_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
name 索引长度为: 编码为utf8mb4,列长为128,不允许为NULL,字段类型为varchar(128)。key_length = 128 * 4 + 0 + 2 = 514;
age 索引长度:int类型占4位,允许null,索引长度为5。
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
扫描行数,也就是说,需要扫描多少行,采能获取目标行数,一般情况下会大于返回行数。通常情况下,rows越小,效率越高,也就有大部分SQL优化,都是在减少这个值的大小。
Tips
: 理想情况下扫描的行数与实际返回行数理论上是一致的,但这种情况及其少,如关联查询,扫描的行数就会比返回行数大大增加)
extra
的信息非常丰富,常见的有:
参考blog → 彻底读懂Mysql执行计划