mysql explain详解
mysql中,使用explain可以模拟优化器执行sql语句,分析查询语句的性能瓶颈。
id:select查询的序号,表示的是查询中执行select子句的顺序。关注该字段获取sql语句各子句的执行顺序
1. id相同表示加载的顺序是从上到下
2. id值越大,优先级越高,越先被执行
select_type:表示对应的子句查询的类型
simple: 简单查询,查询不包含子查询和union
primary: 复杂查询最外层的查询
subquery: 包含再select中的子查询(不在from子句中)
derived: 包含再from子句中的子查询
union: union关键字后的select
table: 该子句正在访问哪个表
type: 表示访问类型,mysql决定如何访问表中的行,需重点关注该字段。
查询性能从优到差依次为:system > const > eq_ref > ref > range > index > all,一般来说,线上查询要到达range级别,最好是ref
system: mysql对查询的某部分转化为一个常量,用于primary key或者unique key与常量进行比较时。system是const的特例,表中只有一行数据时是system。但是当存储引擎是Innodb时,会发现当表只有一行数据时,使用主键进行查询,也是 const,是因为 Innodb 不能可靠地维护表的大小,因此查询优化器不能确认表只有一行,当表的存储引擎换成 MyISAM 时, 可以看到时 system。
const: mysql对查询的某部分转化为一个常量,用于primary key或者unique key与常量进行比较时。
eq_ref: 在 join 查询中,primary key或者unique key索引被连接使用,对于每个索引键值,表中都只有一条记录匹配。
ref: 相比 eq_ref, 不适用唯一索引,而是使用普通索引,索引要和某个值相比较,可能返回多条满足条件的记录。
range: 范围扫描通常出现在the =
, <>
, >
, >=
, <
, <=
, IS NULL
, <=>
, BETWEEN
, LIKE
, or IN()
操作中,使用索引来检索给定范围的行。
index: 扫描索引得出结果,但是不使用索引过滤,类似于 select id from t1。
all: 全表扫描。
key_len: 显示mysql在索引中使用的字节数,通过这个值可以看出查询使用了索引中的哪些列。
1. 所有的索引字段,如果没有设置not null, 需要加1个字节
2. 定长字段,int占4个字节,date占3个字节,char(n) 占 n 个字符
3. 对于不定长字段 varchar(n), 则占 n个字符 + 2个字节
4. 不同的字符集,latin1,1个字符占1个字节;gbk编码的,1个字符占2个字节;utf8编码的,1个字符占3个字节;utf8mb4编码的,1个字符占4个字节
rows: mysql认为执行查询必须检查的行数,是server层的信息,对于innodb类型的表,这个值是不准确的
filtered: condition filter,条件过滤【条件过滤可以使用在连接查询中,驱动表查询条件经过索引过滤后,无法经过索引过滤的查询条件再次经过条件过滤,使得驱动表参与循环的数据量变小】,可以看到,该值越小越好。
如上图所示:query 2 表示经过 idx_status 索引扫描后满足索引过滤条件的数据有 317908 行。优化器预计这些行的 100% (317908 * 100%) 的数据满足搜索条件,会返回query 1进行下一步查询。
query2 使用全表扫描,预计33.33%的数据会满足搜索条件,返回server层进行下一步处理。
这个值对于普通的单表查询没有意义。更应该关注连接查询中的驱动表的该值:
如上图 所示,s1表为驱动表,rows大约为 9688行,filtered为10%,那么驱动表参与循环的数据量为 9688 * 10% 大约为 968行。
Extra:额外信息,重点关注
using Index: 使用了覆盖索引
using Index Condition Pushdown: 索引条件下推优化
using where: 使用where语句来处理查询结果,查询的列未被索引覆盖
using temporary:使用临时表来存储中间结果
using filesort:查询中包含order by排序,但是没有利用索引完成的排序操作