MySQL底层原理-EXPLAIN-《MySQL学习笔记》

admin 2025-11-03 23:39:49 数据库 来源:ZONE.CI 全球网 0 阅读模式
  • 1、id
    • 1.1 单表查询
    • 1.2 子查询
      • 1.2.1 子查询有多个id
      • 1.2.2 子查询仅有一个id
    • 1.3 连接查询
    • 1.4 联合查询
  • 2、select_type
    • 2.1 SIMPLE
    • 2.2 PRIMARY
    • 2.3 UNION
    • 2.4 UNION RESULT
    • 2.5 SUBQUERY
  • 3、table
  • 4、partitions
  • 5、type
  • 6、possible_keys && key
  • 7、key_len
  • 8、ref
  • 9、rows
  • 10、filtered
  • 11、Extra
    • 11.1 No tables used
    • 11.2 Impossible WHERE
    • 11.3 No matching min/max row
    • 11.4 Using index
    • 11.5 Using index condition
    • 11.6 Using where
    • 11.7 Using filesort
    • 11.8 Using temporary
  • 参考

    本文主要参考掘金小册里小孩子的《从根上理解MySQL》,详情见参考文献的前两条。

    一条查询语句经过MySQL查询优化器的基于成本的优化后会生成一个执行计划,这个执行计划展示了接下来具体执行查询的方式,比如多表连接的顺序是什么,是否用到了索引,索引的使用方式等。执行计划可以帮助我们定位慢sql的原因是什么,以及后续sql语句的优化都会基于执行计划。MySQL的Explain命令可以查看查询语句的具体执行计划,使用方式如下:

    1. -- EXPLAIN关键字后面跟具体的sql语句
    2. EXPLAIN SELECT 1;
    3. -- 如果想令展示的结果是json格式,可以在EXPLAIN关键字后面加上FORMAT=JSON
    4. EXPLAIN FORMAT=JSON SELECT 1;

    Explain后的结果举例如下:

    1. mysql> EXPLAIN SELECT 1;
    2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
    3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
    5. | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
    6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
    7. 1 row in set, 1 warning (0.01 sec)

    上面打印的结果就是SELECT 1;这条sql语句的执行计划。下面把执行计划中的各个列的含义先说明一下:

    • id:在一个大的查询语句中每个select关键字都对应一个唯一的id;
    • select_type:select关键字对应的查询类型;
    • table:输出结果集的表;
    • partitions:匹配的分区信息;
    • type:针对单表的访问方法(连接类型);
    • possible_keys:可能用到的索引;
    • key:实际使用到的索引;
    • key_len:实际使用到的索引长度;
    • ref:当使用索引列进行等值查询时,与索引列进行等值匹配的对象信息;
    • rows:预估的需要读取的记录条数;
    • filtered:驱动表中满足查询条件的记录占被驱动表总数的半分比;
    • Extra:一些额外的信息,也很重要。

    下面具体介绍一下每个字段。

    其余的DELETE、INSERT、REPLACE以及UPDATE语句前边都可以加上EXPLAIN,用来查看这些语句的执行计划,只不过SELECT关注的更多些。

    1、id

    查询语句中每出现一个SELECT关键字,MySQL就为他分配一个唯一的id,就是explain结果中的第一列id,具体可以分为以下几种情况:

    • 简单单表查询;
    • 子查询;
    • 连接查询。

      1.1 单表查询

      简单的单表查询中,就仅对一张表进行SELECT,因此只有一行数据,id为1。

      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';
      2. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
      5. | 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | NULL |
      6. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
      7. 1 row in set, 1 warning (0.03 sec)

      1.2 子查询

      1.2.1 子查询有多个id

      对于包含子查询的语句,可能涉及多个SELECT关键字,所以在包含子查询的语句的执行计划中,每个SELECT关键字都会对应一个唯一id,如下:

      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';
      2. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
      5. | 1 | PRIMARY | s1 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9688 | 100.00 | Using where |
      6. | 2 | SUBQUERY | s2 | NULL | index | idx_key1 | idx_key1 | 303 | NULL | 9954 | 100.00 | Using index |
      7. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
      8. 2 rows in set, 1 warning (0.02 sec)

      如上面所示,s1表在外层查询,因此s1表在上面,id分为1,且select_type为PRIMARY;s3表在子查询中,子查询有一个独立的关键字SELECT,因此为子查询分配id为2,且select_type为SUBQUERY。

      1.2.2 子查询仅有一个id

      需要注意的是,优化器可能会对子查询进行重写,将子查询转换为连接查询。因此如果我们想知道优化器对某个子查询是否进行了重写,直接看执行计划即可,比如:

      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key3 FROM s2 WHERE common_field = 'a');
      2. +----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+------------------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+------------------------------+
      5. | 1 | SIMPLE | s2 | NULL | ALL | idx_key3 | NULL | NULL | NULL | 9954 | 10.00 | Using where; Start temporary |
      6. | 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | xiaohaizi.s2.key3 | 1 | 100.00 | End temporary |
      7. +----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+------------------------------+
      8. 2 rows in set, 1 warning (0.00 sec)

      可以看到,虽然我们的查询语句是一个子查询,但是执行计划中s1和s2表对应的记录的id值全部是1,这就表明了查询优化器将子查询转换为了连接查询。

      1.3 连接查询

      对于连接查询,一个select关键字后边的from子句中可以跟随多个表,所以在连接查询的执行计划中,每个表都对应一条记录,但这些记录的id值都是相同的,如下:

      1. mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2;
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
      5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
      6. | 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | Using join buffer (Block Nested Loop) |
      7. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
      8. 2 rows in set, 1 warning (0.01 sec)

      说明:

    • s1和s2分别对应一条记录,但是这两条记录的id都是1,即连接查询中每张表都会对应一条记录,且这些记录的id值相同;

    • 连接查询的执行计划结果中,排在前面的是驱动表,排在后面的是被驱动表,上面例子中s1就是驱动表,s2就是被驱动表。

      1.4 联合查询

      对于UNION子句的查询语句,每个SELECT关键字对应一个id,如下:

      1. mysql> EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;
      2. +----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
      5. | 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
      6. | 2 | UNION | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | NULL |
      7. | NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
      8. +----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
      9. 3 rows in set, 1 warning (0.00 sec)

      最下面一条记录是联合查询时的临时表对应的记录。

      2、select_type

      一个整体的查询语句通过explain生成的执行计划,可能会有若干个小的查询记录,每个小查询都对应一个select_type属性,代表这个小查询是什么查询类型,select_type有以下几种类型:

    • SIMPLE:简单的查询语句,不实用连接查询、子查询、联合查询等;

    • PRIMARY:子查询中最外层的查询;
    • UNION:联合查询中的第二个或者更加后面的SELECT语句;
    • UNION RESULT:联合查询时用来去重的临时表的select_type;
    • SUBQUERY:子查询的select_type;
    • DEPENDENT SUBQUERY:子查询中的第一个SELECT,依赖于外部查询;
    • DERIVED:派生表的SELECT, FROM子句的子查询;
    • UNCACHEABLE SUBQUERY:不常用。

    下面介绍几个常见的。

    2.1 SIMPLE

    查询语句中不包含UNION或者子查询的查询都算作是SIMPLE类型,比方说下边这个单表查询的select_type的值就是SIMPLE:

    1. mysql> EXPLAIN SELECT * FROM s1;
    2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
    3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
    5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
    6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
    7. 1 row in set, 1 warning (0.00 sec)

    当然,连接查询也算是SIMPLE类型,比如:

    1. mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2;
    2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
    3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
    5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
    6. | 1 | SIMPLE | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | Using join buffer (Block Nested Loop) |
    7. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
    8. 2 rows in set, 1 warning (0.01 sec)

    2.2 PRIMARY

    对于包含UNION、UNION ALL或者子查询的大查询来说,它是由几个小查询组成的,其中最左边的那个查询的select_type值就是PRIMARY,比方说:

    1. mysql> EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;
    2. +----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
    3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    4. +----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
    5. | 1 | PRIMARY | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | NULL |
    6. | 2 | UNION | s2 | NULL | ALL | NULL | NULL | NULL | NULL | 9954 | 100.00 | NULL |
    7. | NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
    8. +----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
    9. 3 rows in set, 1 warning (0.00 sec)

    从结果中可以看到,最左边的小查询SELECT * FROM s1对应的是执行计划中的第一条记录,它的select_type值就是PRIMARY。

    2.3 UNION

    对于包含UNION或者UNION ALL的大查询来说,它是由几个小查询组成的,其中除了最左边的那个小查询以外,其余的小查询的select_type值就是UNION,可以对比上一个例子的效果,这就不多举例子了。

    2.4 UNION RESULT

    MySQL选择使用临时表来完成UNION查询的去重工作,针对该临时表的查询的select_type就是UNION RESULT,例子上边有,就不赘述了。

    2.5 SUBQUERY

    如果子查询不能被优化器优化成连接查询,则此时的外层查询对应的select_type是PRIMARY,子查询对应的select_type是SUBQUERY。

    3、table

    每个小查询访问的单表的名称。

    4、partitions

    跟分区表相关,如果没有使用分区表,partitions列的值都是NULL。

    5、type

    type代表每个小查询对表的访问方式,又称为访问类型,常见的类型有:ALL、index、range、fulltext、 ref、eq_ref、const、system、NULL(从左到右,性能从差到好)。

    • ALL:全表扫描;
    • index:index与ALL的区别是ALL类型扫描全表记录,index类型仅遍历索引树,即扫描全部的索引记录;
    • range:仅遍历一个范围区间上的索引记录(比如查询条件是索引列,且条件是在某个区间范围);
    • fulltext:全文索引;
    • ref:使用到了索引,但该索引列的值并不唯一,有重复。这样即使使用索引快速查找到了第一条数据,仍然不能停止,要进行目标值附近的小范围扫描;
    • const:当我们根据主键或者唯一二级索引列与常数进行等值匹配时,对单表的访问方法就是const;
    • system:system是const类型的特例,当查询的表只有一行的情况下是system;
    • NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

      6、possible_keys && key

      在EXPLAIN语句输出的执行计划中,possible_keys列表示在某个查询语句中,对某个表执行单表查询时可能用到的索引有哪些,key列表示实际用到的索引有哪些,比如下面的查询语句:
      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND key3 = 'a';
      2. +----+-------------+-------+------------+------+-------------------+----------+---------+-------+------+----------+-------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+-------------------+----------+---------+-------+------+----------+-------------+
      5. | 1 | SIMPLE | s1 | NULL | ref | idx_key1,idx_key3 | idx_key3 | 303 | const | 6 | 2.75 | Using where |
      6. +----+-------------+-------+------------+------+-------------------+----------+---------+-------+------+----------+-------------+
      7. 1 row in set, 1 warning (0.01 sec)
      上述执行计划的possible_keys列的值是idx_key1,idx_key3,表示该查询可能使用到idx_key1,idx_key3两个索引,然后key列的值是idx_key3,表示经过查询优化器计算使用不同索引的成本后,最后决定使用idx_key3来执行查询比较划算。

      7、key_len

      key_len列表示当优化器决定使用某个索引执行查询时,该索引记录的最大长度(索引中使用的字节数)。不损失精确性的情况下,长度越短越好。

      8、ref

      当使用索引列等值匹配的条件去执行查询时,ref列展示的就是与索引列作等值匹配的东东是个啥,比如只是一个常数或者是某个列。

      9、rows

      如果查询优化器决定使用全表扫描的方式对某个表执行查询时,执行计划的rows列就代表预计需要扫描的行数,如果使用索引来执行查询时,执行计划的rows列就代表预计扫描的索引记录行数。比如下边这个查询:
      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 > 'z';
      2. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
      5. | 1 | SIMPLE | s1 | NULL | range | idx_key1 | idx_key1 | 303 | NULL | 266 | 100.00 | Using index condition |
      6. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
      7. 1 row in set, 1 warning (0.00 sec)
      我们看到执行计划的rows列的值是266,这意味着查询优化器在经过分析使用idx_key1进行查询的成本之后,觉得满足key1 > ‘z’这个条件的记录只有266条。

      10、filtered

      比方说下边这个查询:
      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND common_field = 'a';
      2. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+------------------------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+------------------------------------+
      5. | 1 | SIMPLE | s1 | NULL | range | idx_key1 | idx_key1 | 303 | NULL | 266 | 10.00 | Using index condition; Using where |
      6. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+------------------------------------+
      7. 1 row in set, 1 warning (0.00 sec)
      从执行计划的key列中可以看出来,该查询使用idx_key1索引来执行查询,从rows列可以看出满足key1 > ‘z’的记录有266条。执行计划的filtered列就代表查询优化器预测在这266条记录中,有多少条记录满足其余的搜索条件,也就是common_field = ‘a’这个条件的百分比。此处filtered列的值是10.00,说明查询优化器预测在266条记录中有10.00%的记录满足common_field = ‘a’这个条件。对于单表查询来说,这个filtered列的值没什么意义,我们更关注在连接查询中驱动表对应的执行计划记录的filtered值,比方说下边这个查询:
      1. mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key1 WHERE s1.common_field = 'a';
      2. +----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------+
      5. | 1 | SIMPLE | s1 | NULL | ALL | idx_key1 | NULL | NULL | NULL | 9688 | 10.00 | Using where |
      6. | 1 | SIMPLE | s2 | NULL | ref | idx_key1 | idx_key1 | 303 | xiaohaizi.s1.key1 | 1 | 100.00 | NULL |
      7. +----+-------------+-------+------------+------+---------------+----------+---------+-------------------+------+----------+-------------+
      8. 2 rows in set, 1 warning (0.00 sec)
      从执行计划中可以看出来,查询优化器打算把s1当作驱动表,s2当作被驱动表。我们可以看到驱动表s1表的执行计划的rows列为9688, filtered列为10.00,这意味着驱动表s1的扇出值就是9688 × 10.00% = 968.8,这说明还要对被驱动表执行大约968次查询。

      11、Extra

      Extra列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。MySQL提供的额外信息有好几十个,这里挑常见的说。

      11.1 No tables used

      当查询语句中没有FROM子句时将会提示该额外信息,比如:
      1. mysql> EXPLAIN SELECT 1;
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
      5. | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
      7. 1 row in set, 1 warning (0.00 sec)

      11.2 Impossible WHERE

      查询语句的WHERE子句永远为FALSE时将会提示该额外信息,比方说:
      1. mysql> EXPLAIN SELECT * FROM s1 WHERE 1 != 1;
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
      5. | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------+
      7. 1 row in set, 1 warning (0.01 sec)

      11.3 No matching min/max row

      当查询列表处有MIN或者MAX聚集函数,但是并没有符合WHERE子句中的搜索条件的记录时,将会提示该额外信息,比方说:
      1. mysql> EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = 'abcdefg';
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------------------+
      5. | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No matching min/max row |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------------------+
      7. 1 row in set, 1 warning (0.00 sec)

      11.4 Using index

      当我们的查询列表以及搜索条件中只包含属于某个索引的列,也就是在可以使用索引覆盖的情况下,在Extra列将会提示该额外信息。比方说下边这个查询中只需要用到idx_key1而不需要回表操作:
      1. mysql> EXPLAIN SELECT key1 FROM s1 WHERE key1 = 'a';
      2. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
      5. | 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 100.00 | Using index |
      6. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
      7. 1 row in set, 1 warning (0.00 sec)
      说白了就是当前查询语句满足索引覆盖的条件,extra列就会有using index信息。

      11.5 Using index condition

      如果在查询语句的执行过程中将要使用索引条件下推这个特性,在Extra列中将会显示Using index condition。有些搜索条件中虽然出现了索引列,但却不能使用到索引,比如:
      1. SELECT * FROM s1 WHERE key1 > 'z' AND key1 LIKE '%a';
      其中的key1 > ‘z’可以使用到索引,但是key1 LIKE ‘%a’却无法使用到索引。

      11.6 Using where

      当我们使用全表扫描来执行对某个表的查询,并且该语句的WHERE子句中有针对该表的搜索条件时,在Extra列中会提示上述额外信息。比如下边这个查询:
      1. mysql> EXPLAIN SELECT * FROM s1 WHERE common_field = 'a';
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
      5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 10.00 | Using where |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
      7. 1 row in set, 1 warning (0.01 sec)
      当使用索引访问来执行对某个表的查询,并且该语句的WHERE子句中有除了该索引包含的列之外的其他搜索条件时,在Extra列中也会提示上述额外信息。比如下边这个查询虽然使用idx_key1索引执行查询,但是搜索条件中除了包含key1的搜索条件key1 = ‘a’,还有包含common_field的搜索条件,所以Extra列会显示Using where的提示:
      1. mysql> EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' AND common_field = 'a';
      2. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
      5. | 1 | SIMPLE | s1 | NULL | ref | idx_key1 | idx_key1 | 303 | const | 8 | 10.00 | Using where |
      6. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------------+
      7. 1 row in set, 1 warning (0.00 sec)

      11.7 Using filesort

      有一些情况下对结果集中的记录进行排序是可以使用到索引的,比如下边这个查询:
      1. mysql> EXPLAIN SELECT * FROM s1 ORDER BY key1 LIMIT 10;
      2. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
      5. | 1 | SIMPLE | s1 | NULL | index | NULL | idx_key1 | 303 | NULL | 10 | 100.00 | NULL |
      6. +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------+
      7. 1 row in set, 1 warning (0.03 sec)
      有时查询语句不能直接使用索引进行排序,需要将查询得到的结果集再在内存中进行排序(文件排序),此时执行计划的Extra列中显示Using filesort提示,比如这样:
      1. mysql> EXPLAIN SELECT * FROM s1 ORDER BY common_field LIMIT 10;
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
      5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | Using filesort |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
      7. 1 row in set, 1 warning (0.00 sec)

      11.8 Using temporary

      在许多查询的执行过程中,MySQL可能会借助临时表来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含DISTINCT、GROUP BY、UNION等子句的查询过程中,如果不能有效利用索引来完成查询,MySQL很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行计划的Extra列将会显示Using temporary提示,比方说这样:
      1. mysql> EXPLAIN SELECT DISTINCT common_field FROM s1;
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
      5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | Using temporary |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-----------------+
      7. 1 row in set, 1 warning (0.00 sec)
      再比如:
      1. mysql> EXPLAIN SELECT common_field, COUNT(*) AS amount FROM s1 GROUP BY common_field;
      2. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
      3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
      4. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
      5. | 1 | SIMPLE | s1 | NULL | ALL | NULL | NULL | NULL | NULL | 9688 | 100.00 | Using temporary; Using filesort |
      6. +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------+
      7. 1 row in set, 1 warning (0.00 sec)

      参考

      Explain 详解(上)Explain 详解(下)MySQL Explain详解
    评论:0   参与:  15