1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

[docs add]MySQL执行计划分析

This commit is contained in:
Guide 2023-01-14 18:33:11 +08:00
parent 653d7b59d6
commit 48eab7d0ba
7 changed files with 216 additions and 26 deletions

View File

@ -201,13 +201,14 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
**重要知识点:** **重要知识点:**
- [MySQL数据库索引总结](./docs/database/mysql/mysql-index.md) - [MySQL索引详解](./docs/database/mysql/mysql-index.md)
- [事务隔离级别(图文详解)](./docs/database/mysql/transaction-isolation-level.md) - [MySQL事务隔离级别图文详解)](./docs/database/mysql/transaction-isolation-level.md)
- [MySQL三大日志(binlog、redo log和undo log)详解](./docs/database/mysql/mysql-logs.md) - [MySQL三大日志(binlog、redo log和undo log)详解](./docs/database/mysql/mysql-logs.md)
- [InnoDB 存储引擎对 MVCC 的实现](./docs/database/mysql/innodb-implementation-of-mvcc.md) - [InnoDB 存储引擎对 MVCC 的实现](./docs/database/mysql/innodb-implementation-of-mvcc.md)
- [SQL 语句在 MySQL 中的执行过程](./docs/database/mysql/how-sql-executed-in-mysql.md) - [SQL 语句在 MySQL 中的执行过程](./docs/database/mysql/how-sql-executed-in-mysql.md)
- [关于数据库中如何存储时间的一点思考](./docs/database/mysql/some-thoughts-on-database-storage-time.md) - [MySQL执行计划分析](./docs/database/mysql/mysql-query-execution-plan.md)
- [MySQL中的隐式转换造成的索引失效](./docs/database/mysql/index-invalidation-caused-by-implicit-conversion.md) - [MySQL 时间类型数据存储建议](./docs/database/mysql/some-thoughts-on-database-storage-time.md)
- [MySQL 隐式转换造成索引失效](./docs/database/mysql/index-invalidation-caused-by-implicit-conversion.md)
### Redis ### Redis

View File

@ -244,10 +244,14 @@ export const sidebarConfig = sidebar({
collapsible: true, collapsible: true,
children: [ children: [
"mysql-index", "mysql-index",
"mysql-logs", {
text: "MySQL三大日志详解",
link: "mysql-logs",
},
"transaction-isolation-level", "transaction-isolation-level",
"innodb-implementation-of-mvcc", "innodb-implementation-of-mvcc",
"how-sql-executed-in-mysql", "how-sql-executed-in-mysql",
"mysql-query-execution-plan",
"some-thoughts-on-database-storage-time", "some-thoughts-on-database-storage-time",
"index-invalidation-caused-by-implicit-conversion", "index-invalidation-caused-by-implicit-conversion",
], ],
@ -280,10 +284,7 @@ export const sidebarConfig = sidebar({
text: "MongoDB", text: "MongoDB",
prefix: "mongodb/", prefix: "mongodb/",
icon: "mongodb", icon: "mongodb",
children: [ children: ["mongodb-questions-01", "mongodb-questions-02"],
"mongodb-questions-01",
"mongodb-questions-02",
],
}, },
], ],
}, },

View File

@ -1,5 +1,5 @@
--- ---
title: MySQL中的隐式转换造成索引失效 title: MySQL隐式转换造成索引失效
category: 数据库 category: 数据库
tag: tag:
- MySQL - MySQL

View File

@ -0,0 +1,142 @@
---
title: MySQL执行计划分析
category: 数据库
tag:
- MySQL
head:
- - meta
- name: keywords
content: MySQL基础,MySQL执行计划,EXPLAIN,查询优化器
- - meta
- name: description
content: 执行计划是指一条 SQL 语句在经过MySQL 查询优化器的优化会后,具体的执行方式。优化 SQL 的第一步应该是读懂 SQL 的执行计划。
---
> 本文来自公号 MySQL 技术JavaGuide 对其做了补充完善。原文地址https://mp.weixin.qq.com/s/d5OowNLtXBGEAbT31sSH4g
优化 SQL 的第一步应该是读懂 SQL 的执行计划。本篇文章,我们一起来学习下 MySQL `EXPLAIN` 执行计划相关知识。
## 什么是执行计划?
**执行计划** 是指一条 SQL 语句在经过 **MySQL 查询优化器** 的优化会后,具体的执行方式。
执行计划通常用于 SQL 性能分析、优化等场景。通过 `EXPLAIN` 的结果,可以了解到如数据表的查询顺序、数据查询操作的操作类型、哪些索引可以被命中、哪些索引实际会命中、每个数据表有多少行记录被查询等信息。
## 如何获取执行计划?
MySQL 为我们提供了 `EXPLAIN` 命令,来获取执行计划的相关信息。
需要注意的是,`EXPLAIN` 语句并不会真的去执行相关的语句,而是通过查询优化器对语句进行分析,找出最优的查询方案,并显示对应的信息。
`EXPLAIN` 执行计划支持 `SELECT``DELETE``INSERT``REPLACE` 以及 `UPDATE` 语句。我们一般多用于分析 `SELECT` 查询语句,使用起来非常简单,语法如下:
```sql
EXPLAIN + SELECT 查询语句;
```
我们简单来看下一条查询语句的执行计划:
```sql
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);
+----+-------------+----------+------------+-------+-----------------+---------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+-----------------+---------+---------+------+--------+----------+-------------+
| 1 | PRIMARY | dept_emp | NULL | ALL | NULL | NULL | NULL | NULL | 331143 | 100.00 | Using where |
| 2 | SUBQUERY | dept_emp | NULL | index | PRIMARY,dept_no | PRIMARY | 16 | NULL | 331143 | 100.00 | Using index |
+----+-------------+----------+------------+-------+-----------------+---------+---------+------+--------+----------+-------------+
```
可以看到,执行计划结果中共有 12 列,各列代表的含义总结如下表:
| **列名** | **含义** |
| ------------- | -------------------------------------------- |
| id | SELECT查询的序列标识符 |
| select_type | SELECT关键字对应的查询类型 |
| table | 用到的表名 |
| partitions | 匹配的分区,对于未分区的表,值为 NULL |
| type | 表的访问方法 |
| possible_keys | 可能用到的索引 |
| key | 实际用到的索引 |
| key_len | 所选索引的长度 |
| ref | 当使用索引等值查询时,与索引作比较的列或常量 |
| rows | 预计要读取的行数 |
| filtered | 按表条件过滤后,留存的记录数的百分比 |
| Extra | 附加信息 |
## 如何分析 EXPLAIN 结果?
为了分析 `EXPLAIN` 语句的执行结果,我们需要搞懂执行计划中的重要字段。
### id
SELECT 标识符,是查询中 SELECT 的序号,用来标识整个查询中 SELELCT 语句的顺序。
id 如果相同从上往下依次执行。id 不同id 值越大,执行优先级越高,如果行引用其他行的并集结果,则该值可以为 NULL。
### select_type
查询的类型,主要用于区分普通查询、联合查询、子查询等复杂的查询,常见的值有:
- **SIMPLE**:简单查询,不包含 UNION 或者子查询。
- **PRIMARY**:查询中如果包含子查询或其他部分,外层的 SELECT 将被标记为 PRIMARY。
- **SUBQUERY**:子查询中的第一个 SELECT。
- **UNION**:在 UNION 语句中UNION 之后出现的 SELECT。
- **DERIVED**:在 FROM 中出现的子查询将被标记为 DERIVED。
- **UNION RESULT**UNION 查询的结果。
### table
查询用到的表名,每行都有对应的表名,表名除了正常的表之外,也可能是以下列出的值:
- **`<unionM,N>`** : 本行引用了 id 为 M 和 N 的行的 UNION 结果;
- **`<derivedN>`** : 本行引用了 id 为 N 的表所产生的的派生表结果。派生表有可能产生自 FROM 语句中的子查询。
-**`<subqueryN>`** : 本行引用了 id 为 N 的表所产生的的物化子查询结果。
### type重要
查询执行的类型描述了查询是如何执行的。所有值的顺序从最优到最差排序为system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
常见的几种类型具体含义如下:
- **system**如果表使用的引擎对于表行数统计是精确的MyISAM且表中只有一行记录的情况下访问方法是 system ,是 const 的一种特例。
- **const**:表中最多只有一行匹配的记录,一次查询就可以找到,常用于使用主键或唯一索引的所有字段作为查询条件。
- **eq_ref**:当连表查询时,前一张表的行在当前这张表中只有一行与之对应。是除了 system 与 const 之外最好的 join 方式,常用于使用主键或唯一索引的所有字段作为连表条件。
- **ref**:使用普通索引作为查询条件,查询结果可能找到多个符合条件的行。
- **index_merge**:当查询条件使用了多个索引时,表示开启了 Index Merge 优化,此时执行计划中的 key 列列出了使用到的索引。
- **range**:对索引列进行范围查询,执行计划中的 key 列表示哪个索引被使用了。
- **index**:查询遍历了整棵索引树,与 ALL 类似,只不过扫描的是索引,而索引一般在内存中,速度更快。
- **ALL**:全表扫描。
### possible_keys
possible_keys 列表示 MySQL 执行查询时可能用到的索引。如果这一列为 NULL ,则表示没有可能用到的索引;这种情况下,需要检查 WHERE 语句中所使用的的列,看是否可以通过给这些列中某个或多个添加索引的方法来提高查询性能。
### key重要
key 列表示 MySQL 实际使用到的索引。如果为 NULL则表示未用到索引。
### key_len
key_len 列表示 MySQL 实际使用的索引的最大长度;当使用到联合索引时,有可能是多个列的长度和。在满足需求的前提下越短越好。如果 key 列显示 NULL ,则 key_len 列也显示 NULL 。
### rows
rows 列表示根据表统计信息及选用情况,大致估算出找到所需的记录或所需读取的行数,数值越小越好。
### Extra重要
这列包含了 MySQL 解析查询的额外信息,通过这些信息,可以更准确的理解 MySQL 到底是如何执行查询的。常见的值如下:
- **Using filesort**:在排序时使用了外部的索引排序,没有用到表内索引进行排序。
- **Using temporary**MySQL 需要创建临时表来存储查询的结果,常见于 ORDER BY 和 GROUP BY。
- **Using index**:表明查询使用了覆盖索引,不用回表,查询效率非常高。
- **Using index condition**:表示查询优化器选择使用了索引条件下推这个特性。
- **Using where**:表明查询使用了 WHERE 子句进行条件过滤。一般在没有使用到索引的时候会出现。
- **Using join buffer (Block Nested Loop)**连表查询的方式表示当被驱动表的没有使用索引的时候MySQL 会先将驱动表读出来放到 join buffer 中,再遍历被驱动表与驱动表进行查询。
这里提醒下,当 Extra 列包含 Using filesort 或 Using temporary 时MySQL 的性能可能会存在问题,需要尽可能避免。
## 参考
- https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
- https://juejin.cn/post/6953444668973514789

View File

@ -15,7 +15,7 @@ head:
## MySQL 基础 ## MySQL 基础
### 关系型数据库介绍 ### 什么是关系型数据库?
顾名思义,关系型数据库就是一种建立在关系模型的基础上的数据库。关系模型表明了数据库中所存储的数据之间的联系(一对一、一对多、多对多)。 顾名思义,关系型数据库就是一种建立在关系模型的基础上的数据库。关系模型表明了数据库中所存储的数据之间的联系(一对一、一对多、多对多)。
@ -29,7 +29,7 @@ head:
MySQL、PostgreSQL、Oracle、SQL Server、SQLite微信本地的聊天记录的存储就是用的 SQLite ......。 MySQL、PostgreSQL、Oracle、SQL Server、SQLite微信本地的聊天记录的存储就是用的 SQLite ......。
### MySQL 介绍 ### 什么是 MySQL
![](https://img-blog.csdnimg.cn/20210327143351823.png) ![](https://img-blog.csdnimg.cn/20210327143351823.png)
@ -590,11 +590,56 @@ MySQL 提供了两个方法来处理 ip 地址
### 有哪些常见的 SQL 优化手段? ### 有哪些常见的 SQL 优化手段?
[《Java 面试指北》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7) 的「技术面试题篇」有一篇文章详细介绍了常见的 SQL 优化手段,非常全面,清晰易懂! [《Java 面试指北》(付费)](https://javaguide.cn/zhuanlan/java-mian-shi-zhi-bei.html) 的 **「技术面试题篇」** 有一篇文章详细介绍了常见的 SQL 优化手段,非常全面,清晰易懂!
![常见的 SQL 优化手段](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javamianshizhibei/javamianshizhibei-sql-optimization.png) ![常见的 SQL 优化手段](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/javamianshizhibei/javamianshizhibei-sql-optimization.png)
## 书籍推荐 ### 如何分析 SQL 的性能?
我们可以使用 `EXPLAIN` 命令来分析 SQL 的 **执行计划** 。执行计划是指一条 SQL 语句在经过 MySQL 查询优化器的优化会后,具体的执行方式。
`EXPLAIN` 并不会真的去执行相关的语句,而是通过 **查询优化器** 对语句进行分析,找出最优的查询方案,并显示对应的信息。
`EXPLAIN` 适用于 `SELECT`, `DELETE`, `INSERT`, `REPLACE`, 和 `UPDATE`语句,我们一般分析 `SELECT` 查询较多。
我们这里简单来演示一下 `EXPLAIN` 的使用。
`EXPLAIN` 的输出格式如下:
```sql
mysql> EXPLAIN SELECT `score`,`name` FROM `cus_order` ORDER BY `score` DESC;
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
| 1 | SIMPLE | cus_order | NULL | ALL | NULL | NULL | NULL | NULL | 997572 | 100.00 | Using filesort |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+----------------+
1 row in set, 1 warning (0.00 sec)
```
各个字段的含义如下:
| **列名** | **含义** |
| ------------- | -------------------------------------------- |
| id | SELECT查询的序列标识符 |
| select_type | SELECT关键字对应的查询类型 |
| table | 用到的表名 |
| partitions | 匹配的分区,对于未分区的表,值为 NULL |
| type | 表的访问方法 |
| possible_keys | 可能用到的索引 |
| key | 实际用到的索引 |
| key_len | 所选索引的长度 |
| ref | 当使用索引等值查询时,与索引作比较的列或常量 |
| rows | 预计要读取的行数 |
| filtered | 按表条件过滤后,留存的记录数的百分比 |
| Extra | 附加信息 |
篇幅问题,我这里只是简单介绍了一下 MySQL 执行计划,详细介绍请看:[SQL 的执行计划](./mysql-query-execution-plan.md)这篇文章。
### 读写分离和分库分表了解吗?
读写分离和分库分表相关的问题比较多,于是,我单独写了一篇文章来介绍: [读写分离和分库分表详解](https://javaguide.cn/high-performance/read-and-write-separation-and-library-subtable.html)。
## MySQL 书籍推荐
参见:[https://javaguide.cn/books/database.html#mysql](https://javaguide.cn/books/database.html#mysql) 。 参见:[https://javaguide.cn/books/database.html#mysql](https://javaguide.cn/books/database.html#mysql) 。

View File

@ -1,5 +1,5 @@
--- ---
title: MySQL数据库时间类型数据存储建议 title: MySQL时间类型数据存储建议
category: 数据库 category: 数据库
tag: tag:
- MySQL - MySQL

View File

@ -202,13 +202,14 @@ JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle
**重要知识点:** **重要知识点:**
- [MySQL数据库索引总结](./database/mysql/mysql-index.md) - [MySQL索引详解](./database/mysql/mysql-index.md)
- [事务隔离级别(图文详解)](./database/mysql/transaction-isolation-level.md) - [MySQL事务隔离级别图文详解)](./database/mysql/transaction-isolation-level.md)
- [MySQL三大日志(binlog、redo log和undo log)详解](./database/mysql/mysql-logs.md) - [MySQL三大日志(binlog、redo log和undo log)详解](./database/mysql/mysql-logs.md)
- [InnoDB 存储引擎对 MVCC 的实现](./database/mysql/innodb-implementation-of-mvcc.md) - [InnoDB 存储引擎对 MVCC 的实现](./database/mysql/innodb-implementation-of-mvcc.md)
- [SQL 语句在 MySQL 中的执行过程](./database/mysql/how-sql-executed-in-mysql.md) - [SQL 语句在 MySQL 中的执行过程](./database/mysql/how-sql-executed-in-mysql.md)
- [关于数据库中如何存储时间的一点思考](./database/mysql/some-thoughts-on-database-storage-time.md) - [MySQL执行计划分析](./database/mysql/mysql-query-execution-plan.md)
- [MySQL中的隐式转换造成的索引失效](./database/mysql/index-invalidation-caused-by-implicit-conversion.md) - [MySQL 时间类型数据存储建议](./database/mysql/some-thoughts-on-database-storage-time.md)
- [MySQL 隐式转换造成索引失效](./database/mysql/index-invalidation-caused-by-implicit-conversion.md)
### Redis ### Redis