mysql 8.0.28 查询语句执行顺序实测结果
TL;NRs
根据实测结果,MySQL8.0.28 中 SQL 语句的执行顺序为:
(8) SELECT
(5) DISTINCT <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(4) ON <join_condition>
(2) WHERE <where_condition>
(6) GROUP BY <group_by_list>
(7) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
引言
关于 SQL 语句的执行顺序,常见的是以下版本。然而该版本却与实测结果不符。
(7) SELECT
(8) DISTINCT <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
MySQL 可以通过 EXPLAIN ANALYZE sql_statement 显示真实的执行过程。那么可以通过一个复杂的语句完成测试。
准备数据
准备三个表 t1, t2, t3, 其中数据分别为:



测试
执行以下语句
EXPLAIN ANALYZE
SELECT
DISTINCT COUNT(p.id) AS cnt, COUNT(e.id) AS nn
FROM t1 p
LEFT JOIN t2 q ON p.id > q.id
INNER JOIN t2 w ON q.id < w.id
RIGHT JOIN t3 e ON w.id = e.id
WHERE p.id < 10
GROUP BY p.id
HAVING cnt > 3
ORDER BY cnt DESC, nn DESC
LIMIT 1;
结果为:
-> Limit: 10 row(s) (actual time=0.394..0.395 rows=1 loops=1)
-> Sort with duplicate removal: cnt DESC, nn DESC (actual time=0.393..0.394 rows=1 loops=1)
-> Filter: (cnt > 3) (actual time=0.372..0.374 rows=5 loops=1)
-> Table scan on <temporary> (actual time=0.001..0.001 rows=6 loops=1)
-> Aggregate using temporary table (actual time=0.370..0.372 rows=6 loops=1)
-> Inner hash join (e.id = w.id) (cost=4.73 rows=3) (actual time=0.314..0.324 rows=32 loops=1)
-> Table scan on e (cost=0.13 rows=5) (actual time=0.008..0.016 rows=5 loops=1)
-> Hash
-> Filter: (q.id < w.id) (cost=3.15 rows=3) (actual time=0.265..0.282 rows=32 loops=1)
-> Inner hash join (no condition) (cost=3.15 rows=3) (actual time=0.259..0.271 rows=72 loops=1)
-> Covering index scan on w using PRIMARY (cost=0.13 rows=3) (actual time=0.007..0.010 rows=4 loops=1)
-> Hash
-> Nested loop inner join (cost=2.10 rows=3) (actual time=0.084..0.232 rows=18 loops=1)
-> Filter: (p.id < 10) (cost=1.05 rows=3) (actual time=0.036..0.051 rows=7 loops=1)
-> Table scan on p (cost=1.05 rows=8) (actual time=0.034..0.046 rows=8 loops=1)
-> Filter: (p.id > q.id) (cost=0.13 rows=1) (actual time=0.021..0.025 rows=3 loops=7)
-> Covering index range scan on q (re-planned for each iteration) (cost=0.13 rows=3) (actual time=0.021..0.024 rows=3 loops=7)
结果分析
这是一个调用栈,还原其执行过程为:
筛选 LIMIT 10 {
排序 ORDER BY cnt DESC, nn DESC {
调用 HAVING cnt > 3 过滤器 {
读取临时聚合表 {
聚合 {
第三次联结 RIGHT JOIN t3 e ON w.id = e.id {
扫描表 e ;
第二次联结 INNER JOIN t2 w ON q.id < w.id {
扫描表 w {
使用主键扫描
得到 4 行
}
第一次联结 t1 p LEFT JOIN t2 q ON p.id > q.id {
扫描表 p {
使用 WHERE p.id < 10 过滤器
共 8 行,返回 7 行
}
循环扫描表 q {
7 次循环 {
使用过滤器 ON p.id > q.id
}
}
执行哈希,共 21 行,返回 18 行
}
执行全连接,获得 4 * 18 = 72 行
执行 ON q.id < w.id 过滤器,剩余 32 行
}
执行相等联结 e.id = w.id, 返回 32 行
}
完成所有的联结,获得 32 行
进行聚合 GROUP BY p.id 获得 6 行
}
读取临时聚合表,获得 6 行
}
执行过滤,剩余 5 行
}
去重,剩余 2 行
排序
返回 1 行
}
输出前 1 项
}
可以看到:
- 首先进行表的扫描,也就是所谓的 FROM 第一
- 有主键的表会使用主键索引
- 有索引的表会使用索引
- 有多个表需要扫描时,根据 SQL 语句进行倒序执行
- WHERE 会在表的扫描过程中执行,也就是 WHERE 第二
- 读取到表后,会执行连接
- 有多个联结时,同样是倒序执行
- 首先执行全连接,也就是 JOIN 第三
- 全连接完成后会马上执行 ON 的过滤,也就是 ON 第四
- 完成连接后,会执行去重,也就是 DISTINCT 第五
- 完成去重后,会进行上一层的连接
- 所有连接都完成后,会执行聚合,也就是 GROUP BY 第六
- 聚合完成后,会执行一次扫描,也就是 SELECT 第七
- 扫描结束后,会执行 HAVING 过滤,也就是 HAVING 第八
- 完成过滤后,会进行排序,也就是 ORDER BY 第九
- 最后进行 LIMIT 的限制,也就是 LIMIT 第十
- 需要注意的是,LIMIT 的参数在 sort 函数的返回结果中就已经起作用,合理推测是使用的堆排序
结论
根据实测结果,MySQL8.0.28 中 SQL 语句的执行顺序为:
(8) SELECT
(5) DISTINCT <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(4) ON <join_condition>
(2) WHERE <where_condition>
(6) GROUP BY <group_by_list>
(7) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
mysql 8.0.28 查询语句执行顺序实测结果的更多相关文章
- python 3 mysql sql逻辑查询语句执行顺序
python 3 mysql sql逻辑查询语句执行顺序 一 .SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_t ...
- mysql第四篇--SQL逻辑查询语句执行顺序
mysql第四篇--SQL逻辑查询语句执行顺序 一.SQL语句定义顺序 SELECT DISTINCT <select_list> FROM <left_table> < ...
- SQL逻辑查询语句执行顺序 需要重新整理
一.SQL语句定义顺序 1 2 3 4 5 6 7 8 9 10 SELECT DISTINCT <select_list> FROM <left_table> <joi ...
- SQL学习笔记四(补充-1-1)之MySQL单表查询补充部分:SQL逻辑查询语句执行顺序
阅读目录 一 SELECT语句关键字的定义顺序 二 SELECT语句关键字的执行顺序 三 准备表和数据 四 准备SQL逻辑查询测试语句 五 执行顺序分析 一 SELECT语句关键字的定义顺序 SELE ...
- mysql五补充部分:SQL逻辑查询语句执行顺序
一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...
- mysql 逻辑查询语句执行顺序
一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...
- Mysql补充部分:SQL逻辑查询语句执行顺序
一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...
- 45、SQL逻辑查询语句执行顺序
一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...
- 第四篇:记录相关操作 SQL逻辑查询语句执行顺序
http://www.cnblogs.com/linhaifeng/articles/7372774.html 一 SELECT语句关键字的定义顺序 SELECT DISTINCT <selec ...
随机推荐
- AT32F415 修改时钟和晶振方法(原创)
1. 简介 我们几乎是国内第一批使用AT32F415芯片的客户,那个时候芯片还没涨价,岁月一切静好.使用AT32F415 做了几个小产品,也在持续出货.后来大家都知道,涨价缺货愈演愈烈.好在我们提前囤 ...
- GitHub 简介
用详细的图文对GitHub进行简单的介绍. git是一个版本控制工具,github是一个用git做版本控制的项目托管平台. 主页介绍: overview:总览.相当于个人主页. repositorie ...
- CabloyJS 基于 EggJS 实现的模块编译与发布
背景 现在,EggJS被许多开发团队所采用.有的团队基于商业知识产权的考量,往往会提一个问题:是否可以把EggJS当中的代码编译打包,然后再把代码丑化? 模块编译的机制 EggJS为何不能便利的实现编 ...
- BUUCTF-另一个世界
另一个世界 010editor 打开最下方发现011开头字符串,应该是二进制 得到flag 看也有师傅写的是说八个一组转ascii码,现在也不是很理解啥意思.贴一下其他师傅的python脚本,算出的结 ...
- 记住这几个git命令就够了
git clone: 下载初始化git add:添加git commit -m ' ' :提交 带消息git push:推送git pull: 拉取 git config --global user. ...
- 细说GaussDB(DWS)复杂多样的资源负载管理手段
摘要:对于如此多的管控功能,管控起来实际的效果到底如何,本篇文章就基于当前最新版本,进行效果实测,并进行一定的分析说明. 本文分享自华为云社区<GaussDB(DWS) 资源负载管理:并发管控以 ...
- go-zero微服务实战系列(九、极致优化秒杀性能)
上一篇文章中引入了消息队列对秒杀流量做削峰的处理,我们使用的是Kafka,看起来似乎工作的不错,但其实还是有很多隐患存在,如果这些隐患不优化处理掉,那么秒杀抢购活动开始后可能会出现消息堆积.消费延迟. ...
- 【Nim 游戏】 学习笔记
前言 没脑子选手随便一道博弈论都不会 -- 正文 Nim 游戏引入 这里给出最简单的 \(Nim\) 游戏的题目描述: \(Nim\) 游戏 有两个顶尖聪明的人在玩游戏,游戏规则是这样的: 有\(n\ ...
- HHL论文及代码理解(Generalizing A Person Retrieval Model Hetero- and Homogeneously ECCV 2018)
行人再识别Re-ID面临两个特殊的问题: 1)源数据集和目标数据集类别完全不同 2)相机造成的图片差异 因为一般来说传统的域适应问题源域和目标域的类别是相同的,相机之间的不匹配也是造成行人再识别数据集 ...
- 搭建企业级实时数据融合平台难吗?Tapdata + ES + MongoDB 就能搞定
摘要:如何打造一套企业级的实时数据融合平台?Tapdata 已经找到了最佳实践,下文将以 Tapdata 的零售行业客户为例,与您分享:基于 ES 和 MongoDB 来快速构建一套企业级的实时数 ...