Skip to content
目录概览

如何定位及优化SQL语句的性能问题?

对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了EXPLAIN命令来查看语句的执行计划。

sql
EXPLAIN
SELECT
  r.A 
FROM
  R AS r
  LEFT JOIN S AS s ON r.C = s.C
1
2
3
4
5
6

Mysql执行计划.png

  • id

    执行计划包含的信息 id 有一组数字组成。表示一个查询中各个子查询的执行顺序;

    • id相同执行顺序由上至下。
    • id不同,id值越大优先级越高,越先被执行。
    • id为null时表示一个结果集,不需要使用它查询,常出现在包含union等查询语句中。
  • select_type

    每个子查询的查询类型,一些常见的查询类型如下:

    idselect_typedescription
    1SIMPLE不包含任何子查询或union等查询
    2PRIMARY包含子查询最外层查询就显示为 PRIMARY
    3SUBQUERY在select或 where字句中包含的查询
    4DERIVEDfrom字句中包含的查询
    5UNION出现在union后的查询语句中
    6UNION RESULT从UNION中获取结果集,例如上文的第三个例子
  • table

    查询的数据表,当从衍生表中查数据时会显示 x 表示对应的执行计划id partitions 表分区、表创建的时候可以指定通过那个列进行表分区。 举个例子:

    sql
    create table tmp (
      id int unsigned not null AUTO_INCREMENT,
      name varchar(255),
      PRIMARY KEY (id)
    ) engine = innodb
    partition by key (id) partitions 5;
    
    1
    2
    3
    4
    5
    6
  • type(非常重要)

    可以看到有没有走索引

    • ALL 扫描全表数据
    • index 遍历索引
    • range 索引范围查找
    • index_subquery 在子查询中使用 ref
    • unique_subquery 在子查询中使用 eq_ref
    • ref_or_null 对Null进行索引的优化的 ref
    • fulltext 使用全文索引
    • ref 使用非唯一索引查找数据
    • eq_ref 在join查询中使用PRIMARY KEYorUNIQUE NOT NULL索引关联。
  • possible_keys 可能使用的索引,注意不一定会使用。查询涉及到的字段上若存在索引,则该索引将被列出来。当该列为 NULL时就要考虑当前的SQL是否需要优化了。

  • key 显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。

  • TIPS: 查询中若使用了覆盖索引(覆盖索引:索引的数据覆盖了需要查询的所有数据),则该索引仅出现在key列表中

  • key_length 索引长度

  • ref 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

  • rows 返回估算的结果集数目,并不是一个准确的值。

  • extra

    常见信息如下

    1. Using index 使用覆盖索引
    2. Using where 使用了用where子句来过滤结果集
    3. Using filesort 使用文件排序,使用非索引列进行排序时出现,非常消耗性能,尽量优化。
    4. Using temporary 使用了临时表 sql优化的目标可以参考阿里开发手册

  • SQL性能优化的目标: 至少要达到 range 级别,要求是ref级别,如果可以是consts最好。

    • consts 单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。
    • ref 指的是使用普通的索引(normal index)。
    • range 对索引进行范围检索。

    反例:explain表的结果,type=index,索引物理文件全扫描,速度非常慢,这个index级别比较range还低,与全表扫描是小巫见大巫。