灵魂拷问,SQL 查询语句先执行 SELECT吗?

数据库 MySQL
大家平时和SQL语句打交道的时间肯定不少,有写过简单SQL的,也有为很复杂的业务逻辑的SQL绞尽脑汁的,那我在这里问下大家一个简单的问题:那你知道SQl语句的查询顺序是怎么样的吗?

大家好,我是狼王,一个爱打球的程序员

大家平时和SQL语句打交道的时间肯定不少,有写过简单SQL的,也有为很复杂的业务逻辑的SQL绞尽脑汁的,那我在这里问下大家一个简单的问题:那你知道SQl语句的查询顺序是怎么样的吗?

当我刚看到这个问题的时候,我的内心是这样的

这个问题应该很好回答,毕竟自己已经写了无数个 SQL 查询语句了,有一些还很复杂的。还装不了这个逼了??

[[401526]]

但事实是,我仍然很难确切地说出它的顺序是怎样的。

[[401527]]

好了,不调侃了,我们先来看下SELECT语句的完整语法:

  1. 1. SELECT  
  2. 2. DISTINCT <select_list> 
  3. 3. FROM <left_table> 
  4. 4. <join_type> JOIN <right_table> 
  5. 5. ON <join_condition> 
  6. 6. WHERE <where_condition> 
  7. 7. GROUP BY <group_by_list> 
  8. 8. HAVING <having_condition> 
  9. 9. ORDER BY <order_by_condition> 
  10. 10.LIMIT <limit_number> 

然而其执行顺序却是下面这样的

  1. FROM 
  2. <表名> # 笛卡尔积 
  3. ON 
  4. <筛选条件> # 对笛卡尔积的虚表进行筛选 
  5. JOIN <joinleft joinright join...>  
  6. <join表> # 指定join,用于添加数据到on之后的虚表中,例如left join会将左表的剩余数据添加到虚表中 
  7. WHERE 
  8. <where条件> # 对上述虚表进行筛选 
  9. GROUP BY 
  10. <分组条件> # 分组 
  11. <SUM()等聚合函数> # 用于having子句进行判断,在书写上这类聚合函数是写在having判断里面的 
  12. HAVING 
  13. <分组筛选> # 对分组后的结果进行聚合筛选 
  14. SELECT 
  15. <返回数据列表> # 返回的单列必须在group by子句中,聚合函数除外 
  16. DISTINCT 
  17. # 数据除重 
  18. ORDER BY 
  19. <排序条件> # 排序 
  20. LIMIT 
  21. <行数限制> 

其实,sql引擎在执行上述每一步时,都会在内存中形成一张虚拟表,然后对虚拟表进行后续操作,并释放没用的虚拟表的内存,以此类推。

具体过程如下:(下面“VT”表示 → 虚拟表 virtual )

  • from:select * from table_1, table_2; 与 select * from table_1 join table_2; 的结果一致,都是表示求笛卡尔积;用于直接计算两个表笛卡尔积,得到虚拟表VT1,这是所有select语句最先执行的操作,其他操作是在这个表上进行的,也就是from操作所完成的内容
  • on: 从VT1表中筛选符合条件的数据,形成VT2表;
  • join: 将该 join 类型的数据补充到VT2表中,例如 left join 会将左表的剩余数据添加到虚表VT2中,形成VT3表;若表的数量大于2,则会重复1-3步;
  • where: 执行筛选,(不能使用聚合函数)得到VT4表;
  • group by: 对VT4表进行分组,得到VT5表;其后处理的语句,如select,having,所用到的列必须包含在group by条件中,没有出现的需要用聚合函数;
  • having: 筛选分组后的数据,得到VT6表;
  • select: 返回列得到VT7表;
  • distinct: 用于去重得到VT8表;
  • order by: 用于排序得到VT9表;
  • limit: 返回需要的行数,得到VT10;

需要注意的是:

group by条件中,每个列必须是有效列,不能是聚合函数;

null值也会作为一个分组返回;

除了聚合函数,select子句中的列必须在group by条件中;

上述内容让我们知道一个查询会返回什么,同时,也回答了以下这些问题:

  • 可以在 GRROUP BY 之后使用 WHERE 吗?(不行,GROUP BY 是在 WHERE 之后!)
  • 可以对窗口函数返回的结果进行过滤吗?(不行,窗口函数是 SELECT 语句里,而 SELECT 是在 WHERE 和 GROUP BY 之后)
  • 可以基于 GROUP BY 里的东西进行 ORDER BY 吗?(可以,ORDER BY 基本上是在最后执行的,所以可以基于任何东西进行 ORDER BY)
  • LIMIT 是在什么时候执行?(在最后!)

但是,数据库引擎并不一定严格按照这个顺序执行 SQL 查询,因为为了更快地执行查询,它们会做出一些优化,这些问题会在下方进行解释↓↓↓。

SQL中的别名会影响SQL执行顺序么?

如下方SQL所示:

  1. SELECT  
  2. CONCAT(first_name, ' ', last_name) AS full_name,  
  3. count(*) 
  4. FROM table 
  5. GROUP BY full_name 

从这个语句来看,好像 GROUP BY 是在 SELECT 之后执行的,因为它引用了 SELECT 中的一个别名。但实际上不一定要这样,数据库引擎会把查询重写成这样:

  1. SELECT  
  2. CONCAT(first_name, ' ', last_name) AS full_name,  
  3. count(*) 
  4. FROM table 
  5. GROUP BY CONCAT(first_name, ' ', last_name) 

所以,这样 GROUP BY 仍然先执行。

另外,数据库引擎还会做一系列检查,确保 SELECT 和 GROUP BY 中的东西是有效的,所以会在生成执行计划之前对查询做一次整体检查。

数据库很可能不按正常顺序执行查询(优化)

在实际当中,数据库不一定会按照 JOIN、WHERE、GROUP BY 的顺序来执行查询,因为它们会进行一系列优化,把执行顺序打乱,从而让查询执行得更快,只要不改变查询结果。

这个查询说明了为什么需要以不同的顺序执行查询:

  1. SELECT * FROM 
  2. dept d LEFT JOIN student s  
  3. ON d.student_id = s.id 
  4. WHERE s.name = '狼王' 

如果只需要找出名字叫狼王学生信息,那就没必要对两张表的所有数据执行左连接,在连接之前先进行过滤,这样查询会快得多,而且对于这个查询来说,先执行过滤并不会改变查询结果。

好了。今天就说到这了,我还会不断分享自己的所学所想,希望我们一起走在成功的道路上!

 

责任编辑:姜华 来源: 狼王编程
相关推荐

2019-10-23 08:45:34

SQL数据库开发

2020-01-29 19:24:59

SQL数据库MySQL

2022-12-12 08:46:11

2010-09-03 14:47:50

SQLSELECT语句

2022-03-16 18:27:39

开发低代码软件开发

2010-09-03 15:39:24

SQLSelect语句

2020-06-02 07:44:04

AQS JavaNode

2019-11-06 09:30:35

SQL查询语句数据库

2019-08-01 10:20:10

2010-09-03 14:39:15

SQLSELECT语句

2020-05-22 08:13:45

敏捷开发OKR

2010-11-11 11:37:22

SQL SELECT语

2020-06-22 13:48:08

SQL查询SELECT

2010-09-03 15:27:02

SQLSELECT语句

2021-06-02 09:47:48

RSA2021

2023-03-30 09:10:06

SQLSELECTFROM

2022-09-01 16:42:47

MySQL数据库架构

2024-03-06 08:18:22

语句GreatSQL

2022-08-26 01:10:32

TCPSYNLinux

2022-07-28 09:13:30

MySQL数据库
点赞
收藏

51CTO技术栈公众号