使用 explain 优化你的 mysql 性能

本文是关于在学习《高性能 Mysql》附录 D 中关于 Explain 如何获取执行计划信息相关总结。MySQL 提供了一个 EXPLAIN 命令,它能够对 SELECT 语句进行分析,获取优化器对当前查询的执行计划,以供开发人员针对相关 SQL 进行优化。在 SELECT 语句前加上 Explain 就能够查看到相关信息, 例如:mysql

EXPLAIN SELECT * from user_info WHERE id < 300;

复制代码

Explain 特色

  • explain 返回的结果是以表为粒度的,每一个表输出一行,这里的表示广义上的表,能够是一个子查询,也能够是一个 UNION 后的结果。
  • 并非全部的 explain 都不执行查询,若是 FROM 子句里包含了子查询,那么 MySql 实际上会执行子查询之外层对于外层查询的优化。
  • explain 没法告诉咱们触发器,存储过程以及 UDF 是如何影响查询的
  • explain 对于内存排序和临时文件排序都使用 “filesort”
  • explain 对于磁盘上的临时表和内存上的临时表都使用 “Using temporary”
  • explain 只能解析 Select 查询,对于 update,insert 等都不支持,咱们可使用 select 来模拟 update 操做近似获取 update 的执行过程

Explain 中的列

id

SELECT 查询的标识符. 每一个 SELECT 都会自动分配一个惟一的标识符.sql

select_type

select_type 表示了查询的类型, 它的经常使用取值有:segmentfault

  • SIMPLE:表示此查询不包含 UNION 查询或子查询
  • SUBQUERY:包含在 Select 列表中的子查询,也就是不在 FROM 子句中的子查询
  • DERIVED:表示包含在 From 子句中的 Select 查询
  • UNION:表示此查询是 UNION 的第二和随后的查询
  • UNION RESULT: 从 UNION 匿名临时表检索结果的 SELECT
  • PRIMARY, 表示此查询是最外层的查询
  • DEPENDENT UNION: UNION 中的第二个或后面的查询语句, DEPENDENT 意味着 Select 依赖于外层查询中发现的数据
  • DEPENDENT SUBQUERY: 包含在 Select 列表中的子查询, 但子查询依赖于外层查询的结果.
table

查询的是哪一个表,mysql 查询优化器执行的关联顺序并不和咱们写 SQL 时关联的顺序一致,下面咱们讲一下 Mysql 是如何对关联查询做优化的:性能优化

  • Mysql 查询执行计划老是按照左侧深度优先树的规则去执行,也就是从一个表开始一直嵌套循环,并不会相似平衡二叉树同样两个分支同时执行
  • 在多表关联时,能够经过多种不一样的关联顺序获取相同的执行结果,查询优化器会评估不一样的顺序选择一个代价最小的关联查询
  • 若是你不想要优化器改变你的关联顺序,可使用 STRAIGHT JOIN 关键字强制使用你的关联顺序去执行
  • 若是关联表特别多时,超过 optimizer_search_depth 的限制时,优化器评估每一种关联顺序的执行成本过高,这时会选择“贪婪”的搜索模式
type

type 字段比较重要, 它提供了判断查询是否高效的重要依据依据. 经过 type 字段, 咱们判断这次查询是全表扫描仍是索引扫描等,type 类型的性能比较,一般来讲, 不一样的 type 类型的性能关系以下:bash

ALL < index < range < ref < eq_ref < const < system < NULL服务器

  • NULL:这种访问意味着 Mysql 能在优化阶段分解查询语句,在执行阶段不须要访问表或者索引
  • system: 预先知道整个表中只有一条数据. 这个类型是特殊的 const 类型
# 由于表中backend_user是主键,因此子查询里最多能够选出一条数据,因此最外层查询的type是system,里层查询的type是const
explain select * from (select * from backend_user where id = 1) a;
复制代码
  • const:针对主键或惟一索引的等值查询扫描, 最多只返回一行数据. const 查询速度很是快, 由于它仅仅读取一次便可
  • eq_ref: 此类型一般出如今多表的 join 查询, 表示对于前表的每个结果, 都只能匹配到后表的一行结果. 而且查询的比较操做一般是 =, 查询效率较高.
  • ref:此类型一般出如今多表的 join 查询, 针对于非惟一或非主键索引, 或者是使用了最左前缀规则索引的查询,可能会查询出多个值
  • range: 表示使用索引范围查询, 经过索引字段范围获取表中部分数据记录. 这个类型一般出如今 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN() 操做中。可是对于一样的 type = range 的查询,性能上仍是有区别的:
# 虽然是都是范围查询,其实第二个查询时多个等值条件查询
# 对于第一个查询,mysql 没法再使用该列后面的其它查询索引了,而第二个则能够继续使用索引
select id from actor where id > 45 and class_id = 3;
select id from actor where id in (44, 47, 48) and class_id = 3;
复制代码
  • index: 表示经过索引进行全表扫描和 ALL 类型相似, 有点是避免了排序,肯定是须要承担按照索引次序读取表的开销。若是 Extra 列中出现了 “Using index” 代表是用了覆盖索引,此时开销很是小。
  • ALL: 表示全表扫描, 这个类型的查询是性能最差的查询之一。通常状况下都会从头至尾扫描全部行,除非使用了 Limit 或者 Extra 列中显示 “Using distinct/not exists”。
possible_keys

这次查询中可能选用的索引,这些索引列是根据查询的列以及比较操做符来判断的,可能在后续的真实查询中没有用到也有可能性能

key

这次查询中确切使用到的索引,若是在 possible_keys 中没有出现而在 key 中出现,说明优化器可能出于另外缘由好比选择覆盖索引,因此 possiable_keys 揭示了哪个索引有助于高效进行查找,而 key 显示了采用哪个索引能够最小化查询成本。学习

key_len

表示查询优化器使用了索引的字节数. 这个字段能够评估组合索引是否彻底被使用, 或只有最左部分字段被使用到,好比咱们建了一个组合索引(col1, col2),那么以下两条查询虽然用到的都是这个组合索引,可是对应的key_len的只是不同的。key_len 显示了在索引字段中可能的最大长度,而不是数据使用的实际字节数优化

select * from table1 where col1 = 1;
select * from table1 where col1 = 1 and col2 = 2;
复制代码
ref

这一列显示了以前的表在 key 列记录的索引中查找值所用的列或者常量ui

rows

rows 也是一个重要的字段. MySQL 查询优化器根据统计信息, 估算 SQL 要查找到结果集须要扫描读取的数据行数。这个值很是直观显示 SQL 的效率好坏, 原则上 rows 越少越好。

  • 经过把每一个表的 rows 值相乘能够粗略的估算出整个查询要检查的行数
  • 这个值只是一个估算的值,不是实际查出来的值
filtered

filtered 是在 MYSQL 5.1 中加进来的,在使用 EXPLAIN EXTENDED 时出现,表示此查询条件所过滤的数据的百分比,将 rows 除以 filtered 能够估算出整个表数据行数。

Extra

EXplain 中的不少额外的信息会在 Extra 字段显示, 常见的有如下几种内容:

  • Using filesort

当 Extra 中有 Using filesort 时, 表示 MySQL 需额外的排序操做, 不能经过索引顺序达到排序效果. 通常有 Using filesort, 都建议优化去掉, 由于这样的查询 CPU 资源消耗大。 可是 Explain 不会告诉你 Mysql 将使用文件排序仍是内存排序:

-- 好比咱们创建索引为:KEY `user_product_detail_index` (`user_id`, `product_name`, `productor`),那么以下两个查询

EXPLAIN SELECT * FROM order_info ORDER BY product_name;    -- Using filesort,不能经过索引进行排序,须要优化
EXPLAIN SELECT * FROM order_info ORDER BY user_id, product_name;-- 无 Using filesort,经过索引进行排序,优化成功
复制代码
  • Using index

"覆盖索引扫描", 表示查询在索引树中就可查找所需数据, 不用扫描表数据文件, 每每说明性能不错

  • Using where

这意味着 Mysql 服务器在存储引擎检索行后再进行过滤,通常出现 “Using where” 会受益于不一样的索引

  • Using temporary

查询有使用临时表, 通常出现于排序, 分组和多表 join 的状况, 临时表多是内存临时表或者文件临时表

partitions

在 Mysql 5.1 版本中引入了 EXPLAIN PARTITIONS 能够显示查询将访问的分区状况

参考文献

相关文章
相关标签/搜索