查询计划参数详解

explain这是这次想要了解的重点命令,用于查看mysql中查询sql语句的执行计划,用来对sql进行优化,以最合理的方式写sql语句
一条标准的sql查询语句:

explain select id from user_customer where id=1\G;

得到的结果:

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: user_customer
   partitions: NULL
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index

从上面可以看到所有的参数,下面一一进行说明:

id

select查询的标识符,每个select都会被自动分配一个唯一的标识符

select_type

select 查询的类型,常见的值如下:

  • SIMPLE:表示此查询不包含UNION查询或子查询

  • PRIMARY:表示此查询是最外层的查询

  • UNION:表示此查询是UNION的第二或随后的查询

  • DEPENDENT UNION:UNION中的第二个或后面的查询语句,取决于外面的查询

  • UNION RESULT:UNION的结果

  • SUBQUERY:子查询中的第一个SELECT

  • DEPENDEND SUBQUERY:子查询中的第一个SELECT,取决于外面的查询,即子查询依赖于外层查询的结果

  • DERIVED:被驱动的select子查询(子查询位于FROM子句)

  • MATERIALIZED:被物化的子查询

table

查询涉及到的数据表或衍生表

type

type字段比较重要,它标识了查询是否高效,是使用了全表扫描还是索引扫描等等

  • system:表中只有一条数据,这个类型是特殊的const类型

  • const:针对主键或唯一索引的等值查询扫描,最多只返回一条数据。const查询的速度非常快,因为它仅仅读取一次即可,如下面的sql语句

select * from user_customer where id=5;
  • ref:此类型通常出现在多表的join查询,针对于非唯一或非主键索引,或者是使用了最左前缀规则索引的查询

select * from user_customer where first_name='123' and last_name='456';

explain select * from migrations,user_customer  where migrations.batch=user_customer.uid and cid>1\G;

eq_ref:通常出现在多表的join查询,对于对于前表的每一个结果,都只能匹配到后表的一行结果,并且查询的比较操作是=,查询效率较高

explain select * from migrations,user_customer  where migrations.batch=user_customer.uid \G;    //前表的数据在后表中都有匹配
  • range:range表示的索引范围查找,通过索引字段范围获取表中部分数据记录,这个类型通常出现在=, <>, >, <, between, in()等操作中
    typerange时,那么explain输出的ref字段为NULL,并且ken_len字段为此次查询中使用到的索引的最长的那个

    > int的长度是4字节,bigint的长度是8字节;字符串根据字段的长度可以计算出长度(**utf每个字符占用3字节,如果是varchar**);如果字段允许null则会增加一个字节的大小
    
  • index:表示扫描的时候仅仅扫描了索引,而不扫描数据;也就是说在查询数据的时候直接在索引树中就可以获取到,在这种情况下的时候,extra字段会显式Using Index

  • all:表示全表扫描,是所有这些属性中性能最差的一个

type类型的性能比较

all < index < range ~ index_merge < ref < eq_ref < const < system

possible_keys

表示在查询的过程中有可能使用到的keys

ken_len

表示查询优化器使用到了的索引的字节数,这个字段可以评估出组合索引是否被完全使用到,或只有最左部分字段被使用到,key_len的计算规则如下:

  • 字符串

    • char(n):固定长度,n字符长度,根据不同的编码n2或n3的字节

    • varchar(n):变长长度,在实际计算存储大小的时候,n小于255则用1字节存储长度,大于255则用2字节存储长度

  • 数值类型

    • tinyint(n):1字节

    • smallint(n):2字节

    • mediumint(n):3字节

    • int(n):4字节

    • bitint(n):8字节

  • 时间类型

    • date:3字节

    • timestamp:4字节

    • datetime:8字节

  • 字段属性:

    • Null属性占用一个字节,如果字段是NOT NULL的,则不会占用这额外的一字节

    • 在数值类型中,是预留出了一位去存储数值的符号

rows

mysql查询优化器根据统计信息,估算sql要查找结果集需要扫描读取的数据行数,这个值可以直观的反映出sql的效率,原则上rows数值越小越好

extra

在sql中很多额外的信息会在extra字段中体现:

  • Using filesort
    当Extra字段中有Using filesort时,表示mysql需要额外的排序操作,不能通过索引顺序达到排序效果;在sql语句中使用order by 进行排序的时候,如果没有很好的使用到定值和最左排序的话,会出现这种情况

  • Using index condition

    • 这是mysql5.6的新特性,叫索引条件推送,只是针对于二级索引。

    • 在一般情况下,mysql服务器都会将存储引擎处理完成的数据返回给服务层后在应用where条件进行过滤,但是当mysql筛选到where条件中的第一个条件筛选的方式是类似于范围查询,就是like<等;但是这里mysql的查询优化器会筛选第一个where条件中的能够查询出的范围,会根据range的范围与数据的总数进行对比进行什么样的查询

    • 查询想要获取的字段都是*

  • Using index
    “覆盖索引扫描”,表示查询在索引树上就可以找到所需要的数据,而不需要扫描底层的叶子节点数据,这种情况性能很好

只出现了这个的时候表示性能很好;如果这个和Using where同时出现的话,表示先在存储引擎中使用索引进行筛选,再在mysql服务中进行条件筛选

  • Using temporary
    在查询的时候使用临时表,一般出现排序,分组和多表join的情况,查询效率不高,建议进行优化

  • Using where
    使用了where从句来限制哪些行将与下一个表匹配或者是返回给用户

Extra列出现Using where表示mysql服务器将存储引擎返回服务层以后再应用where条件过滤
有一种情况,数据表中数据量很大,查询的条件在数据表中占的比例也很高,本来在原则上可以使用索引,但是因为该查询记录占表中比例很大,mysql会不对该sql使用索引,这种情况可以在查询语句后面使用limit进行限制

  • Using MRR
    这也是mysql5.6新增的特性, Multi-Range Read(多范围读),针对基于辅助/第二索引的查询,减少随机IO,并且将随机IO转换为顺序IO,提高查询效率

在基于mysql中的Innodb的数据存储方式才用的是B+tree,二级索引的存储顺序与主键的顺序是不一致的,开启了mrr之后,mysql将根据辅助结果集获取的结果集根据主键进行排序,将乱序化为有序,可以用主键访问基表,将随机读转换为顺序读,多页数据记录可一次性读入或根据此次的主键范围分次读入,以减少IO操作,提高查询效率

  • Not exists
    mysql优化了left join,一旦它找到了匹配left join标准的行,就不再搜索了

    原文作者:坏掉的牙
    原文地址: https://segmentfault.com/a/1190000008545314
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞