本文基于MySQL官方5.7版本的 MySQL 5.7 Reference Document.
DESC、DESCRIBE和EXPLAIN这三个关键字都是我们常用的,但是使用场景不同。从MySQL解析器的角度而言,他们的实际用法是一致的。
即实际使用过程中 DESC 等价于 DESCRIBE 等价于 EXPLAIN 。我们常常用于以下两种场景:
建立两张数据表,用于后续的测试调用。
CREATE TABLE `department` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(50) NOT NULL COMMENT '部门名称',
`depart_desc` varchar(50) DEFAULT NULL COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES ('1', 'IT部', '程序猿');
INSERT INTO `department` VALUES ('2', '人事部', '很多美女');
INSERT INTO `department` VALUES ('3', '施工部', '糙汉子');
INSERT INTO `department` VALUES ('4', '财务部', '千万别惹他们!');
INSERT INTO `department` VALUES ('5', '行政部', '生活大管家');
-- ----------------------------
-- Table structure for user
-- ----------------------------
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`age` int(11) DEFAULT NULL,
`depart_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `user_index_1` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('2', 'Jack', '20', '1');
INSERT INTO `user` VALUES ('3', 'Mike', '25', '1');
INSERT INTO `user` VALUES ('4', 'Lucy', '22', '2');
INSERT INTO `user` VALUES ('5', 'Mircle', '30', '3');
INSERT INTO `user` VALUES ('6', 'Josn', '45', '4');
INSERT INTO `user` VALUES ('7', 'Sgodon', '30', '5');
1. 执行语法
{EXPLAIN | DESCRIBE | DESC}
tbl_name [col_name | wild]
2. 调用实例
mysql> DESC user;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | MUL | NULL | |
| age | int(11) | YES | | NULL | |
| depart_id | int(11) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)
-----------------------------------------------------------------
mysql> EXPLAIN user;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | MUL | NULL | |
| age | int(11) | YES | | NULL | |
| depart_id | int(11) | YES | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
4 rows in set (0.02 sec)
使用EXPLAIN和DESC的效果是一样的,相类似的语法有 SHOW CREATE TABLE.
1.执行语法
{EXPLAIN | DESCRIBE | DESC}
[explain_type]
{explainable_stmt | FOR CONNECTION connection_id}
explain_type: {
EXTENDED
| PARTITIONS
| FORMAT = format_name
}
format_name: {
TRADITIONAL
| JSON
}
explainable_stmt: {
SELECT statement
| DELETE statement
| INSERT statement
| REPLACE statement
| UPDATE statement
}
2.调用示例
mysql> EXPLAIN SELECT * FROM user WHERE id = 4 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
1 row in set (0.00 sec)
#试一下用法-EXTENDED:多了一列 filtered
mysql> EXPLAIN EXTENDED SELECT * FROM user WHERE id= 4 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)
#试一下用法-PARTITIONS:多了一列partitions
mysql> EXPLAIN PARTITIONS SELECT * FROM user WHERE id=4 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
partitions: NULL
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
1 row in set (0.00 sec)
#试一下用法-FORMAT = JSON:默认就为Traditional
mysql> EXPLAIN FORMAT = JSON SELECT id FROM user WHERE id = 4 \G
*************************** 1. row ***************************
EXPLAIN: {
"query_block": {
"select_id": 1,
"table": {
"table_name": "user",
"access_type": "const",
"possible_keys": [
"PRIMARY"
],
"key": "PRIMARY",
"used_key_parts": [
"id"
],
"key_length": "4",
"ref": [
"const"
],
"rows": 1,
"filtered": 100,
"using_index": true
}
}
}
3.EXPLAIN输出格式
mysql> EXPLAIN SELECT * FROM user WHERE id = 4 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
1 row in set (0.00 sec)
select_type
大部分的查询都是SIMPLE,没有子查询和UNION连接。我们试一下 子查询和UNION。
#使用子查询输出结果如下:
mysql> EXPLAIN SELECT name,age FROM user WHERE depart_id = (SELECT id FROM department WHERE name='人事部门')\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: user
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 6
Extra: Using where
*************************** 2. row ***************************
id: 2
select_type: SUBQUERY
table: department
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 5
Extra: Using where
2 rows in set (0.00 sec)
----------------------------------------------------------------------------
#使用Union查询输出结果如下:
#union<1,2> 和使用union语句是相对应的,1、2指的是查询ID的序号
mysql> EXPLAIN SELECT name,age FROM user WHERE depart_id = 1 UNION SELECT name,age FROM user WHERE depart_id=2 \G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: user
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 6
Extra: Using where
*************************** 2. row ***************************
id: 2
select_type: UNION
table: user
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 6
Extra: Using where
*************************** 3. row ***************************
id: NULL
select_type: UNION RESULT
table:
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra: Using temporary
3 rows in set (0.00 sec)
table
有以下几种形式:
-
mysql> EXPLAIN SELECT u.name,u.age FROM (SELECT * FROM user WHERE depart_id=2) u \G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table:
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 6
Extra: NULL
*************************** 2. row ***************************
id: 2
select_type: DERIVED
table: user
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 6
Extra: Using where
2 rows in set (0.00 sec)
type
# full_3 只有一条数据,但是调用全表查询时还是使用的ALL
mysql> SELECT * FROM full_3;
+----+------+------+-------------+
| id | pkid | name | create_time |
+----+------+------+-------------+
| 1 | 1 | 3 | NULL |
+----+------+------+-------------+
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM full_3 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: full_3
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
Extra: NULL
1 row in set (0.00 sec)
# 通过这样的子查询时可以的
mysql> EXPLAIN SELECT d.* FROM (SELECT * FROM full_3 fu WHERE fu.id=1) d \G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table:
type: system
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
Extra: NULL
*************************** 2. row ***************************
id: 2
select_type: DERIVED
table: fu
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
2 rows in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM user WHERE id =3 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: const
rows: 1
Extra: NULL
1 row in set (0.00 sec)
eq_ref: 此类型通常出现在多表的 join 查询, 表示对于前表的每一个结果, 都只能匹配到后表的一行结果. 并且查询的比较操作通常是 =, 查询效率较高.
ref: 此类型通常出现在多表的 join 查询, 针对于非唯一或非主键索引, 或者是使用了 最左前缀 规则索引的查询.
例如下面这个例子中, 就使用到了 ref 类型的查询:
mysql> EXPLAIN SELECT name FROM user WHERE name = 'Jack' \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: ref
possible_keys: user_index_1
key: user_index_1
key_len: 152
ref: const
rows: 1
Extra: Using where; Using index
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM user WHERE name LIKE 'Jack'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: range
possible_keys: user_index_1
key: user_index_1
key_len: 152
ref: NULL
rows: 1
Extra: Using index condition
1 row in set (0.00 sec)
#如果用=就变成REF
mysql> EXPLAIN SELECT name FROM user WHERE name != 'Jack' \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: index
possible_keys: user_index_1
key: user_index_1
key_len: 152
ref: NULL
rows: 6
Extra: Using where; Using index
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT name FROM user WHERE age = 1 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 6
Extra: Using where
1 row in set (0.00 sec)
possible_keys
possibel_keys表示MySQL在查询过程中能够用到的索引,但是不一定会使用。具体使用的索引,由Key决定。
key
key这一列是MySQL真正使用的索引。
ken_len
key_len 表示查询优化器使用了索引的字节数. 这个字段可以评估组合索引是否完全被使用, 或只有最左部分字段被使用到。
rows
rows列显示MySQL执行查询预计会覆盖的行数,这个值越小越好。
Extra
有很多额外信息,举三个例子简单说明下。
Impossible WHERE noticed after reading const tables
预示着Where列有逻辑问题,可能一直是FALSE,无法获取数据。例如:
mysql> EXPLAIN SELECT * FROM user WHERE id >3 AND id<2 \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra: Impossible WHERE noticed after reading const tables
1 row in set (0.00 sec)
Using filesort
查询结果进行排序,例如:
mysql> EXPLAIN SELECT * FROM user WHERE id >3 ORDER By age \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: range
possible_keys: PRIMARY
key: PRIMARY
key_len: 4
ref: NULL
rows: 4
Extra: Using where; Using filesort
1 row in set (0.00 sec)
Using index
覆盖索引,从辅助索引中就能够得到需要的数据,而不需要查询聚集索引中的记录。
mysql> EXPLAIN SELECT name FROM user WHERE name LIKE 'I%' \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: user
type: range
possible_keys: user_index_1
key: user_index_1
key_len: 152
ref: NULL
rows: 1
Extra: Using where; Using index
1 row in set (0.00 sec)