每日MySQL之020:使用EXPLAIN查看SQL的执行计划

MySQL中要查看执行计划,可以使用EXPLAIN命令,EXPLAIN 使用的对象是 SELECT, DELETE, INSERT, REPLACE, 和 UPDATE 语句。将EXPLAIN换成DESCRIBE也行,两者含义一样,但实际操作中一般用DESCRIBE查看表结构,用EXPLAIN查看执行计划。输出的结果不是图形化的,而是一张表。对于每个SELECT语句中的每个表,EXPLAIN都会返回一行。返回的顺序就是MySQL读取表的顺序。MySQL使用nested-loop join来完成所有的join工作。

先来看两个简单的例子,第一个SELECT语句访问一张表,只有一行输出。第二个SELECT语句访问两张表,就有两行输出,table列指定了访问的表名:

mysql> EXPLAIN SELECT id, age from t1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT t1.id, t1.age, t2.name FROM t1,t2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                 |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
|  1 | SIMPLE      | t2    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |   100.00 | NULL                                  |
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+---------------------------------------+
2 rows in set, 1 warning (0.01 sec)

再详细看一下各个字段的含义,假设我们有以下三张表:

mysql> CREATE TABLE `t1` (id int, age int, KEY `idx1` (`id`));
mysql> CREATE TABLE `t2` ( `id` int(11),`name` char(15));
mysql> CREATE TABLE `t3` (id int not null primary key, name char(30));

mysql> INSERT INTO `t1` VALUES (1001,24),(1002,25),(1003,43),(1004,44),(1006,31),(1005,23);
mysql> INSERT INTO `t2` VALUES (1002,'name1'),(1005,'name2'),(1007,'name3'),(1010,'name4');
mysql> INSERT INTO `t3` VALUES (10086, 'Mobile'),(10011, 'Unicom'),(95583,'CommercialBank'),(12355,'taxiBue'),(1010,'aa');

mysql> ANALYZE TABLE t1;
mysql> ANALYZE TABLE t2;
mysql> ANALYZE TABLE t3;

mysql> select * from t1;
+------+------+
| id   | age  |
+------+------+
| 1001 |   24 |
| 1002 |   25 |
| 1003 |   43 |
| 1004 |   44 |
| 1006 |   31 |
| 1005 |   23 |
+------+------+
6 rows in set (0.01 sec)

mysql> select * from t2;
+------+-------+
| id   | name  |
+------+-------+
| 1002 | name1 |
| 1005 | name2 |
| 1007 | name3 |
| 1010 | name4 |
+------+-------+
4 rows in set (0.00 sec)

mysql> select * from t3;
+-------+----------------+
| id    | name           |
+-------+----------------+
|  1010 | aa             |
| 10011 | Unicom         |
| 10086 | Mobile         |
| 12355 | taxiBue        |
| 95583 | CommercialBank |
+-------+----------------+
5 rows in set (0.00 sec)

id (JSON name: select_id)
SELECT ID, 查询语句中SELECT的编号。如果是union的结果,可能为空值,这时table column显示的是。 

示例1: 第一个语句有两个SELECT语句,所以有两个id,第二个语句有三个SELECT,所以有三个id,UNION RESULT的id为空:

mysql> EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2;
+----+--------------+------------+
| id | select_type  | table      |
+----+--------------+------------+
|  1 | PRIMARY      | t1         |
|  2 | UNION        | t2         |
|NULL| UNION RESULT |  |
+----+--------------+------------+
3 rows in set, 1 warning (0.00 sec)

mysql> EXPLAIN SELECT * FROM t1 UNION SELECT * FROM t2 UNION SELECT * FROM t3;
+----+--------------+--------------+
| id | select_type  | table        |
+----+--------------+--------------+
|  1 | PRIMARY      | t1           |
|  2 | UNION        | t2           |
|  3 | UNION        | t3           |
|NULL| UNION RESULT |  |
+----+--------------+--------------+
4 rows in set, 1 warning (0.00 sec)


select_type (JSON name: none)
SIMPLE:简单查询(不使用UNION或者子查询)
PRIMARY: 最外边SELECT
UNION: UNION中第二个及以后的SELECT

参考示例1。

table (JSON name: table_name)
表名。

partitions (JSON name: partitions)
分区表的分区名,对于非分区表,为NULL

type (JSON name: access_type)
Join type,可以参考:链接http://blog.csdn.net/qingsong3333/article/details/77149845

possible_keys (JSON name: possible_keys)
可能选择的索引

key (JSON name: key)
最终选择的索引

示例2,第一条SELECT没有使用索引, 第二条使用了索引idx1,第三条使用了PRIMARY KEY。

mysql> EXPLAIN SELECT * FROM t1 where id < 1005;
+----+-------------+-------+...+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table |...| possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+...+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    |...| idx1          | NULL | NULL    | NULL |    6 |    66.67 | Using where |
+----+-------------+-------+...+---------------+------+---------+------+------+----------+-------------+

mysql> EXPLAIN SELECT * FROM t1 where id > 1004;
+----+-------------+-------+...+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table |...| possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+...+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t1    |...| idx1          | idx1 | 5       | NULL |    2 |   100.00 | Using index condition |
+----+-------------+-------+...+---------------+------+---------+------+------+----------+-----------------------+

mysql> EXPLAIN SELECT * FROM t3 where id > 10010;
+----+-------------+-------+...+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table |...| possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+...+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t3    |...| PRIMARY       | PRIMARY | 4       | NULL |    4 |   100.00 | Using where |
+----+-------------+-------+...+---------------+---------+---------+------+------+----------+-------------+

key_len (JSON name: key_length)
key的长度

rows (JSON name: rows)
MySQL认为完成查询需要访问的行数,只是个估计值。

filtered (JSON name: filtered)
被条件过滤掉的百分比。That is, rows shows the estimated number of rows examined and rows × filtered / 100
shows the number of rows that will be joined with previous tables.

Extra (JSON name: none)
额外说明

另外,可以设置 FORMAT 参数,如果设为JSON,则显示为JSON格式:
mysql> EXPLAIN FORMAT=JSON SELECT id, age from t1 \G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "2.20"
    },
    "table": {
      "table_name": "t1",
      "access_type": "ALL",
      "rows_examined_per_scan": 6,
      "rows_produced_per_join": 6,
      "filtered": "100.00",
      "cost_info": {
        "read_cost": "1.00",
        "eval_cost": "1.20",
        "prefix_cost": "2.20",
        "data_read_per_join": "96"
      },
      "used_columns": [
        "id",
        "age"
      ]
    }
  }
}
1 row in set, 1 warning (0.00 sec)

你可能感兴趣的:(MYSQL)