MySQL的语句执行顺序

MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是 FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明 的,但是只有最后一个虚拟的表才会被作为结果返回。如果没有在语句中指定某一个子句,那么将会跳过相应的步骤。

(8)SELECT (9)DISTINCT<select_list>
(1)FROM<left_table>
(3)<join_type>JOIN<right_table>
(2)        ON<jion_condition>
(4)WHERE<where_condition>
(5)GROUP BY<group_by_list>
(6)WITH{CUBE|ROLLUP}
(7)HAVING<having_condition>
(8)ORDER BY<order_by_list>
(11)LIMIT<limit_member>

 

下面我们来具体分析一下查询处理的每一个阶段

  1. FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1

  2. ON: 对虚表VT1进行ON筛选,只有那些符合<join-condition>的行才会被记录在虚表VT2中。

  3. JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为 止。

  4. WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表VT4中。

  5. GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.

  6. CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.

  7. HAVING: 对虚拟表VT6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表VT7中。

  8. SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。

  9. DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.

  10. ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.

  11. LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。

MySQL 语句存在逻辑执行顺序和物理执行顺序。逻辑执行顺序是一个概念模型,用于理解 SQL 的行为和规则;而物理执行顺序方面,MySQL 的查询优化器为提高效率可能会对其进行改变,例如将 WHERE 条件下推到存储引擎层以便在读取数据时就进行过滤,还可能根据统计信息和索引决定 JOIN 的顺序 [^1]。 标准查询语句的逻辑执行顺序如下: 1. 执行 `FROM`、`JOIN` 确定表之间的连接关系,得到初步的数据 [^2]。 2. 使用 `WHERE` 对数据进行普通的初步筛选 [^2]。 3. 通过 `GROUP BY` 进行分组,各组分别执行 `HAVING` 中的普通筛选或者聚合函数筛选 [^2]。 4. 执行 `SELECT`,可以是普通字段查询也可以是获取聚合函数的查询结果,若为集合函数,`SELECT` 的查询结果会新增一条字段 [^2]。 5. 对查询结果进行去重操作 `DISTINCT` [^2]。 6. 合并各组的查询结果,按照 `ORDER BY` 的条件进行排序 [^2]。 以一个具体的 SQL 语句为例: ```sql SELECT DISTINCT user.name FROM user JOIN vip ON user.id = vip.id WHERE user.id > 10 GROUP BY user.mobile HAVING COUNT(*) > 2 ORDER BY user.id LIMIT 3; ``` 其执行顺序为: 1. `FROM user JOIN vip ON user.id = vip.id`:确定 `user` 表和 `vip` 表的连接关系 [^4]。 2. `WHERE user.id > 10`:对连接后的数据进行初步筛选,筛选出 `user.id` 大于 10 的数据 [^4]。 3. `GROUP BY user.mobile`:根据 `user.mobile` 进行分组 [^4]。 4. `HAVING COUNT(*) > 2`:在分组后的数据中,使用聚合函数 `COUNT(*)` 统计每组的数量,并筛选出数量大于 2 的分组 [^4]。 5. `SELECT user.name`:从分组聚合完的表中挑选出需要查询的字段 `user.name` [^4]。 6. `DISTINCT`:对查询出来的数据进行去重操作 [^4]。 7. `ORDER BY user.id`:对去重后的数据按照 `user.id` 进行排序 [^4]。 8. `LIMIT 3`:对排序后的数据选出前面 3 条 [^4]。 在执行器层面,若表有相应权限,会打开表继续执行。若表的 `ID` 字段没有索引,执行器会调用 InnoDB 引擎接口取表的第一行,判断 `ID` 值是否符合条件,符合则存入结果集,不符合则跳过,然后调用引擎接口取“下一行”,重复判断逻辑,直到取到表的最后一行,最后将满足条件的行组成的记录集作为结果集返回给客户端。对于有索引的表,执行逻辑类似,第一次调用“取满足条件的第一行”接口,之后循环取“满足条件的下一行”接口。数据库慢查询日志中的 `rows_examined` 字段表示语句执行过程中扫描的行数,该值在执行器每次调用引擎获取数据行时累加,但引擎扫描行数跟 `rows_examined` 并非完全相同 [^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值