《高性能MySQL》第七章 MySQL 执行计划优化

通过 EXPLAIN 对 SQL 语句的执行计划进行分析,以此来判断一条 SQL 的执行效率,并作出对应的优化调整。

EXPLAIN 能够分析 select update insert replace delete 这些SQL。

一、执行计划分析

  1. SQL 如何使用索引
    1. 并不是某一列上存在索引,sql 在执行时就必定会使用该索引。
  2. 联接查询的执行顺序
  3. 查询扫描的数据行数

二、执行计划中的内容

以下面的查询SQL 为例,解释执行计划中输出内容的含义

EXPLAIN
SELECT customer_id,title,content 
FROM `product_comment`
WHERE audit_status = 1
AND product_id = 199726
LIMIT 0,5
  • id: 1
    • ID 列中的数据为一组数字,表示执行 SELECT 语句的顺序
    • ID 值相同时,执行顺序由上至下
    • ID 值越大优先级越高,执行越靠前
  • select_type: SIMPLE
    • SIMPLE:不包含子查询或是 UNION 操作的查询
    • PRIMARY:查询中如果包含任何子查询,那么最外层的查询则被标记为 PRIMARY
    • SUBQUERY:SELECT 列表中的子查询
    • DEPENDENT SUBQUERY:依赖外部结果的子查询
    • UNION:Union操作的第二个或是之后的查询的值为 union
    • DEPENDENT UNION:当 UNION 作为子查询时,第二或是第二个后的查询的 select_type 值
    • UNION RESULT:UNION 产生的结果集
    • DERIVED:出现在 FROM 子句中的子查询
  • table: product_comment
    • 输出数据行所在的表的名称
    • <unionM,N>由ID 为 M,N 查询union 产生的结果集
    • / 由 ID 为N 的查询结果的结果集
  • partition: NULL
    • 对于分区表,显示查询的分区ID
    • 对于非分区表,显示为 NULL
  • type: ALL
    • 以下类型的性能从高到低依次排列
    • system:这是 const 联接类型的一个特例,当查询的表只有一行时使用
    • const:表中有且只有一个匹配的行时使用,如对主键或是唯一索引的查询,这是效率最高的联接方式
    • eq_ref:唯一索引或是主键索引查找,对于每个索引键,表中只有一条记录与之匹配
    • ref:非唯一索引查找,返回匹配某个单独值的所有行
    • ref_or_null:类似于 ref 类型的查询,但是附加了对 NULL 值列的查询
    • index_merge:该联接类型表示使用了索引合并优化方法
    • range:索引范围扫描,常见于 between、>、< 这样的查询条件
    • index:FULL index Scan 全索引扫描,同ALL 的区别是,遍历的是索引树
    • ALL:FULL Table Scan 全表扫描,这是效率最差的联接方式
  • possible_keys: NULL
    • 指出 MySQL 能使用哪些索引来优化查询,基于查询所使用到的列和过滤条件来判断的
    • 查询列所涉及到的列上的索引都会被列出,但不一定会被使用
  • key: NULL
    • 查询优化器优化查询实际所使用的索引
    • 如果没有可用的索引,则显示为 NULL
    • 如果查询使用了覆盖索引,则该索引仅出现在 Key 列中
  • key_len: NULL
    • 表示索引字段的最大可能长度
    • ken_len的长度由字段定义计算而来,并非数据的实际长度
  • ref: NULL
    • 表示那些列或常量被用于查找索引列上的值
  • rows: 9400
    • 表示 MySQL 通过索引统计信息,估算的所需读取的行数
    • Rows 值的大小是个统计抽样结果,并不十分准确
  • filtered: 1.00
    • 表示返回结果的行数占需读取行数的百分比
    • Filtered 列的值越大越好,越大表示过滤的比例越高,最大100%
    • Filtered 列的值依赖统计信息,并不十分准确
  • Extra: Using where
    • Distinct:优化 distinct 操作,在找到第一匹配的元素后即停止找同样值的动作
    • Not exists:使用 not exists 来优化操作
    • Using filesort:使用额外操作进行排序,通常会出现在 order by 或 group by 查询中
    • Using index:使用了覆盖索引进行查询
    • Using teporary:MySQL 需要使用临时表来处理查询,常见于排序、子查询和分组查询
    • Using where:需要在 MySQL 服务器层使用 WHERE 条件来过滤数据
    • select tables optimized away:直接通过索引来获取数据,不用访问表

通过上面的查询语句,以及索引的设计规范,应该在 where 语句查询的部分设置索引,这里使用联合索引。

-- 查询表中,audit_status和product_id 的区分度,应该将区分度高的列放在联合索引的左侧
SELECT COUNT(DISTINCT audit_status)/COUNT(*) AS audit_rate,
COUNT(DISTINCT product_id)/COUNT(*) AS product_rate
FROM product_comment;

假设 product_rate = 0.8 ,audit_rate = 0.2,则联合索引应该设计为:

CREATE INDEX idx_productID_auditStatus
ON product_comment(product_id,audit_status);

执行计划的限制

  1. 无法展示存储过程、触发器、UDF 对查询的影响
  2. 无法使用 EXPLAIN 对存储过程进行分析
  3. 早期版本的MySQL 只支持对 SELECT 语句进行分析

《高性能MySQL》目录

  1. 第一章 数据库设计规范
  2. 第二章 数据库字段设计规范
  3. 第三章 数据库 SQL 开发规范
  4. 第四章 数据库操作行为规范
  5. 第五章 设计数据库分区表
  6. 第六章 MySQL存储引擎
  7. 第七章 MySQL 执行优化
  8. 第八章 MySQL 慢查询日志
  9. 第九章 MySQL 数据库备份与恢复
  10. 第十章 MySQL构架拆分
  11. 其他:MySQL表结构实践sql
  12. 其他2:MySQL常用命令
文章作者: koral
文章链接: http://luokaiii.github.io/2019/06/17/读书笔记/《高性能MySQL》/7.MySQL执行计划优化/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自