笠缪

Menu

MySQL EXPLAIN 详解

说明:以下语法基于 MariaDB-10.3.29

什么是 EXPLAIN

MySQL 在执行SQL语句之前,会通过查询优化器基于各种成本和规则的优化后生成一条所谓的执行计划。这个执行计划展示了具体执行的查询方式,比如多表连接的顺序,以及对于每个表采用什么访问方式来具体执行查询等等。

MySQL 在设计的时候提供了 EXPLAIN 语句来查看某个查询语句的具体执行计划。

标准语法

MariaDB [test]> explain select * from test;
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
|    1 | SIMPLE      | test  | ALL  | NULL          | NULL | NULL    | NULL |    3 |       |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.000 sec)

其实除了select 外,像 delete,insert,replace和update都可以加上explain,用来查看这些语句的执行计划,只不过大家select用的多些。

### explain insert
MariaDB [test]> explain insert into test (`test`) values ('11111');
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
| id   | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
|    1 | INSERT      | test  | ALL  | NULL          | NULL | NULL    | NULL | NULL | NULL  |
+------+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.000 sec)

### explain update
MariaDB [test]> explain update test set test = 111 where id = 2;
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id   | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|    1 | SIMPLE      | test  | range | PRIMARY       | PRIMARY | 4       | NULL |    1 | Using where |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set (0.000 sec)

...

看看explain 各个字段的含义

id

在一个大的查询语句中每个select关键字对应一个唯一的id

select_type

select关键字对应的那个查询类型

type

针对表的访问方法

效率对比

system > const > eq_ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > all

possible_keys

可能用到的索引,并不是越多越好,可能用的索引越多,查询优化器计算成本时耗时更长,尽量删除不必要的索引

key

经过优化器计算后实际上使用的索引

key_len

实际使用索引的长度,由一下三部分组成

  1. 固定长度类型,实际占用存储空间的最大值就是固定值,例如:int key_ken = 4字节;指定字符集的变长类型,实际占用最大存储空间通过计算后得出,例如:utf-8 字符集,变长 vachar(100) key_len = 100 * 3 字节

  2. 如果索引列可以存储null值,则key_len比不可以存储null值时多1个字节

  3. 变长字段都会有2个字节的空间来存储该变长列的实际长度

例如:

  1. 不允许为null值的 int 类型的列,key_len = 4

  2. 允许为null值的int 类型的列,key_len = 5

  3. 不允许为null值的 vachar(100),key_len = 100 * 3 + 2 = 302

ref

当使用索引列等值查询时,与索引列进行等值匹配的对象信息

rows

预估需要读取的记录条数

extra

额外的信息

执行计划json格式输出

语法:explain 后加 format=json

例如:
explain format=json select * from t1;

mysql> explain format = json select * from t1 where id in (select id from t2);
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                               |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| {
  "query_block": {
    "select_id": 1,
    "table": {
      "table_name": "<subquery2>",
      "access_type": "ALL",
      "possible_keys": ["distinct_key"],
      "rows": 1,
      "filtered": 100,
      "materialized": {
        "unique": 1,
        "query_block": {
          "select_id": 2,
          "table": {
            "table_name": "t2",
            "access_type": "ALL",
            "rows": 1,
            "filtered": 100
          }
        }
      }
    },
    "block-nl-join": {
      "table": {
        "table_name": "t1",
        "access_type": "ALL",
        "rows": 2,
        "filtered": 100
      },
      "buffer_type": "flat",
      "buffer_size": "256Kb",
      "join_type": "BNL",
      "attached_condition": "t1.`id` = t2.`id`"
    }
  }
} |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
— 于 共写了14151个字
— 标签: