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 ...
 
随机推荐
- Fail2ban 术语
			
filter 过滤器,使用正则表达式定义一个过滤器,从日志中匹配到IP.端口等. action 动作,定义在指定时间段要执行的操作. jail 监禁,jail是一个filter和一个action或者多 ...
 - v87.01 鸿蒙内核源码分析 (内核启动篇) | 从汇编到 main () | 百篇博客分析 OpenHarmony 源码
			
本篇关键词:内核重定位.MMU.SVC栈.热启动.内核映射表 内核汇编相关篇为: v74.01 鸿蒙内核源码分析(编码方式) | 机器指令是如何编码的 v75.03 鸿蒙内核源码分析(汇编基础) | ...
 - 记一次IIS网站启动不了的问题排查
			
今天清理了下机器中的IIS网站,将很久不用的网站都删除. 因为需要删除的比较多,正在使用的很少,就将网站全部删除了,然后准备重新添加需要用的. 在添加了网站后,点击启动按钮,发现网站启动不了,因为网站 ...
 - 聊聊 C# 中的多态底层 (虚方法调用) 是怎么玩的
			
最近在看 C++ 的虚方法调用实现原理,大概就是说在 class 的首位置存放着一个指向 vtable array 指针数组 的指针,而 vtable array 中的每一个指针元素指向的就是各自的 ...
 - datax在解析完配置后,会将core.json,job.json,plugin.json合并内容
			
{ "common": { "column": { "dateFormat": "yyyy-MM-dd", " ...
 - JAVA - 如果hashMap的key是一个自定义的类,怎么办?
			
JAVA - 如果hashMap的key是一个自定义的类,怎么办? 使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals().
 - 认识一下什么是JSP
			
摘要:JSP,全称是Java Server Pages,即Java服务器页面,是由Sun Microsystems公司主导创建的一种动态网页技术标准. 本文分享自华为云社区<Java服务器页面- ...
 - php个性代码注释
			
// _ooOoo_ // o8888888o // 88" . "88 // (| -_- |) // O\ = /O // ____/`---'\____ // . ' \ ...
 - 1.1 操作系统的第一个功能——虚拟化硬件资源 -《zobolの操作系统学习札记》
			
1.1 操作系统的第一个功能--虚拟化硬件资源 目录 1.1 操作系统的第一个功能--虚拟化硬件资源 问1:操作系统一般处于计算机系统的哪一个位置? 问2:管理硬件资源为什么要单独交给操作系统? 问3 ...
 - JavaScript有哪些数据类型,它们的区别?
			
基本数据类型:number.string.boolean.Undefined.NaN(特殊值).BigInt.Symbol 引入数据类型:Object NaN是JS中的特殊值,表示非数字,NaN不是数 ...