《高性能MySQL》EXPLAIN

前言

调用 EXPLAIN 来获取关于查询执行计划的信息与输出

调用 EXPLAIN

  1. 使用:在 SELECT 关键字之前增加 EXPLAIN
    image-20190127172115882

  2. 每个表在输出中只有一行,若多表关联,则输出多行

  • 这里的表的定义:可以是一个子查询,一个 UNION 结果
  • EXPLAIN 的两个主要变种
    • EXPLAIN EXTENDED
      • 服务器 “逆向编译” 执行计划为一个 SELECT 语句(SHOW WARNINGS 后能看到
      • 额外增加一个 filtered 列
    • EXPLAIN PARTITIONS
      • 显示查询将访问的分区
  1. EXPLAIN 查询时,会执行子查询并将其结果放在一个临时表中,然后完成外层查询优化

  2. EXPLAIN 返回的只是个近似结果

  3. EXPLAIN 相关的限制

  • 无法知道触发器、存储过程或 UDF 如何影响查询

  • 不支持存储过程(单可以单独抽取查询进行 EXPLAIN

  • 无法知道查询执行中所做的特定优化

  • 不会显示关于查询的执行计划的所有信息

  • 无法区分具有相同名字的事物

    • 内存排序 和 临时文件 都使用 filesort
    • 磁盘上和内存中的临时表都显示 Using temporary
  • 可能会误导(对一个有着小 LIMIT 的查询显示 全索引扫描

重写非 SELECT 查询

  1. EXPLAIN 只能解释 SELECGT 查询,无法对 INSERT、UPDATE、DELETE 或其他语句做解释

  2. 可通过重写某些非 SELECT 查询以利用 EXPLAIN

    • 转化成一个等价的访问所有相同列的 SELECT
    • 任何提及的列都必须在 SELECT 列表,关联子句 或者 WHERE 子句中
  3. 显示计划时,对于写查询并没有“等价”的读查询

    • 读只需要找到数据的一份副本并返回
    • 写需要查找并修改其所有副本(消耗更高

EXPLAIN 中的列

  1. id 列

    • 总是包含一个编码,标识 SELECT 所属的行

    • 简单查询类型

    • 复杂查询类型

      • 简单子查询
      • 派生表
      • UNION
    • UNION 结果总是放在一个匿名临时表中(它的 id 列是 NULL

  2. select_type 列

    • SIMPLE
      • 不包括子查询和 UNION
    • PRIMARY
      • 查找中存在复杂的子部分,最外层部分标记为 PRIMARY
    • SUBQUERY
      • SELECT 列表中的子查询中的 SELECT
    • DERIVED
      • FROM 子句的子查询中的 SELECT(派生表
    • UNION
      • 在 UNION 中的第二个和随后的 SELECT 被标记为 UNION
    • UNION RESULT
      • 从 UNION 的匿名临时表检索结果的 SELECT
    • DEPENDENT
      • SELECT 依赖与外层查询中发现的数据
    • UNCACHEABLE
      • SELECT 中的某些特性阻止结果被缓存于一个 Item_cache 中
  3. table 列

    • 显示对应行正在访问哪个表
    • MySQL 的查询执行计划总是左侧深度优先树
      image-20190127185947881
  4. type 列

    • 显示了 关联类型(访问类型
    • 常用的访问类型(性能依次从最差到最优
      • ALL
        • 全表扫描(存在例外,例如使用了 LIMIT 或 Extra 列中显示 Using distinct/not exists
      • index
        • 类似于全表扫描,只是扫描时按索引次序进行
        • 优点:可以避免排序
        • 缺点:承担按索引次序读取整个表的开销(意味着按随机次序访问行,开销较大
      • range
        • 有限制的索引扫描(范围扫描
        • IN ( ) 和 OR 列表使用时均显示为 范围扫描,但两者其实是相当不同的访问类型,性能差异较大
      • ref
        • 索引访问(索引查找),返回所有匹配某个单个值的行
        • 使用场景:使用非唯一索引时 或 唯一索引的非唯一性前缀时
        • ref_or_null(变体):MySQL 必须在初次查找的结果里进行第二次查找以找出 NULL 条目
      • eq_ref
        • 最多只返回一条符合条件的记录
        • 使用场景:使用主键 或 唯一索引时
      • const ,system
        • MySQL 能对查询的某部分进行优化并将其转换成一个常量时
      • NULL
        • MySQL 能再优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引
  5. possible_keys 列

    • 显示查询可能使用哪些索引
  6. key 列

    • 显示 MySQL 决定采用哪个索引来优化对该表的访问(基于最小化查询成本
    • 该索引可能不存在 possible_keys 列中(可能选择了一个覆盖索引,哪怕没有 WHERE 子句
  7. key_len 列

    • 显示 MySQL 在索引里使用的字节数(具体使用到的该索引上的某些列
    • key_len 通过查找表的定义而被计算出,而不是表中的数据
  8. ref 列

    • 显示在 key 列记录的索引中查找值所用的列或常量
  9. rows 列

    • 显示 MySQL 估计为了找到所需要的行而要读取的行数(嵌套循环管理计划里的嵌套数目
    • 该数字只是 MySQL 认为它要检查的行数,而不是结果集里的行数
  10. filtered 列

- 使用 EXPLAIN EXTEND 时才会出现
- 显示 针对表里符合某个条件的记录数的百分比所做的一个悲观估算
  - 只有在使用 ALL、index、range 和 index_merge 访问时才会用到这一估算
  1. Extra 列
  • 显示不适合在其他列显示的额外信息
  • 常见重要的值
    • Using index(覆盖索引
    • Using index condition(ICP 索引条件下推
    • Using where(Mysql 服务器将在存储引擎检索后再进行过滤
    • Using temporary(对查询结果排序时会使用一个临时表
    • Using filesort(对结果使用一个外部索引排序,详情请看:《高性能 MySQL》查询性能优化
    • Range checked for each record(没有好用的索引,新索引将在联接的每一行上重新估算

MySQL 5.6 中的改进

  • 能对类似于 UPDATE、INSERT等的查询进行解释
  • 对查询优化和执行引擎的一系列改进
    • 允许匿名的临时表尽可能晚地被具体化
    • 可直接解释带子查询的查询语句,而不需要先实际地执行子查询
  • 增加优化跟踪功能的方式改进优化器
发布了98 篇原创文章 · 获赞 197 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/YangDongChuan1995/article/details/86906605