Skip to content

Commit df19c6a

Browse files
committed
docs:MySQL执行计划分析新增测试案例
1 parent 8627578 commit df19c6a

File tree

1 file changed

+72
-15
lines changed

1 file changed

+72
-15
lines changed

docs/database/mysql/mysql-query-execution-plan.md

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,33 @@ MySQL 为我们提供了 `EXPLAIN` 命令,来获取执行计划的相关信息
2929
MySQL 8.0.18 引入了 `EXPLAIN ANALYZE`,它会**真正执行**查询并输出每个步骤的实际耗时与行数,比标准 `EXPLAIN` 的估算数据更可靠,适合在测试环境深度排查慢查询:
3030

3131
```sql
32-
EXPLAIN ANALYZE SELECT * FROM dept_emp WHERE emp_no = 10001;
32+
mysql> EXPLAIN ANALYZE SELECT * FROM users WHERE age = 25\G
33+
*************************** 1. row ***************************
34+
EXPLAIN: -> Covering index lookup on users using idx_age_score_name (age=25)
35+
(cost=1.52 rows=12) (actual time=0.0272..0.0344 rows=12 loops=1)
3336
```
3437

3538
此外,`EXPLAIN FORMAT=JSON` 可以输出优化器的成本模型数据(`query_cost`),比表格形式更能反映各步骤的实际代价,在多表 JOIN 或子查询调优时尤为有用:
3639

3740
```sql
38-
EXPLAIN FORMAT=JSON SELECT * FROM dept_emp WHERE emp_no = 10001;
41+
mysql> EXPLAIN FORMAT=JSON SELECT * FROM users WHERE age = 25\G
42+
*************************** 1. row ***************************
43+
EXPLAIN: {
44+
"query_block": {
45+
"select_id": 1,
46+
"cost_info": {
47+
"query_cost": "1.52"
48+
},
49+
"table": {
50+
"table_name": "users",
51+
"access_type": "ref",
52+
"key": "idx_age_score_name",
53+
"rows_examined_per_scan": 12,
54+
"filtered": "100.00",
55+
"using_index": true
56+
}
57+
}
58+
}
3959
```
4060

4161
`EXPLAIN` 执行计划支持 `SELECT``DELETE``INSERT``REPLACE` 以及 `UPDATE` 语句。我们一般多用于分析 `SELECT` 查询语句,使用起来非常简单,语法如下:
@@ -46,14 +66,29 @@ EXPLAIN SELECT 查询语句;
4666

4767
我们简单来看下一条查询语句的执行计划:
4868

69+
**示例 1:单表查询(使用索引)**
70+
71+
```sql
72+
-- 表结构:users(id, age, score, name, address),联合索引 idx_age_score_name(age, score, name)
73+
mysql> EXPLAIN SELECT * FROM users WHERE age = 25;
74+
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------------+
75+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
76+
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------------+
77+
| 1 | SIMPLE | users | NULL | ref | idx_age_score_name | idx_age_score_name | 5 | const | 12 | 100.00 | Using index |
78+
+----+-------------+-------+------------+------+---------------------+---------------------+---------+-------+------+----------+-------------+
79+
```
80+
81+
**示例 2:UNION 查询(id 为 NULL 的场景)**
82+
4983
```sql
50-
mysql> explain SELECT * FROM dept_emp WHERE emp_no IN (SELECT emp_no FROM dept_emp GROUP BY emp_no HAVING COUNT(emp_no)>1);
51-
+----+-------------+----------+------------+-------+-----------------+---------+---------+------+--------+----------+-------------+
52-
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
53-
+----+-------------+----------+------------+-------+-----------------+---------+---------+------+--------+----------+-------------+
54-
| 1 | PRIMARY | dept_emp | NULL | ALL | NULL | NULL | NULL | NULL | 331143 | 100.00 | Using where |
55-
| 2 | SUBQUERY | dept_emp | NULL | index | PRIMARY,dept_no | PRIMARY | 16 | NULL | 331143 | 100.00 | Using index |
56-
+----+-------------+----------+------------+-------+-----------------+---------+---------+------+--------+----------+-------------+
84+
mysql> EXPLAIN SELECT * FROM users WHERE id = 1 UNION SELECT * FROM users WHERE id = 2;
85+
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
86+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
87+
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
88+
| 1 | PRIMARY | users | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
89+
| 2 | UNION | users | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
90+
| 3 | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
91+
+----+--------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
5792
```
5893

5994
可以看到,执行计划结果中共有 12 列,各列代表的含义总结如下表:
@@ -90,12 +125,28 @@ mysql> explain SELECT * FROM dept_emp WHERE emp_no IN (SELECT emp_no FROM dept_e
90125
**示例**
91126

92127
```sql
93-
EXPLAIN SELECT * FROM dept_emp WHERE emp_no = 10001
94-
UNION
95-
SELECT * FROM dept_emp WHERE dept_no = 'd001';
128+
mysql> EXPLAIN SELECT * FROM users WHERE id = 1
129+
-> UNION
130+
-> SELECT * FROM users WHERE id = 2\G
131+
*************************** 1. row ***************************
132+
id: 1
133+
select_type: PRIMARY
134+
table: users
135+
type: const
136+
*************************** 2. row ***************************
137+
id: 2
138+
select_type: UNION
139+
table: users
140+
type: const
141+
*************************** 3. row ***************************
142+
id: NULL
143+
select_type: UNION RESULT
144+
table: <union1,2>
145+
type: ALL
146+
Extra: Using temporary
96147
```
97148

98-
输出中最后一行的 `id = NULL`,table = `<union1,2>`,表示这是前两个查询结果的合并。
149+
第三行的 `id = NULL`,table = `<union1,2>`,表示这是前两个查询结果的合并。
99150

100151
### select_type
101152

@@ -180,10 +231,16 @@ rows 列表示根据表统计信息及索引选用情况,**估算**出找到
180231

181232
```sql
182233
-- 执行计划估算行数
183-
EXPLAIN SELECT * FROM dept_emp WHERE emp_no = 10001;
234+
mysql> EXPLAIN SELECT * FROM users WHERE age = 25\G
235+
rows: 12
184236

185237
-- 实际行数(注意:在大表上慎用 COUNT(*))
186-
SELECT COUNT(*) FROM dept_emp WHERE emp_no = 10001;
238+
mysql> SELECT COUNT(*) FROM users WHERE age = 25;
239+
+----------+
240+
| COUNT(*) |
241+
+----------+
242+
| 12 |
243+
+----------+
187244
```
188245

189246
遇到执行计划与实际性能不符时,可以执行 `ANALYZE TABLE` 重新采样,再观察执行计划的变化。

0 commit comments

Comments
 (0)