当前位置: 首页 > 科技观察

灵魂拷问,SQL查询是否先执行SELECT?

时间:2023-03-19 14:37:38 科技观察

大家好,我是狼王,一个爱打球的程序员。您必须花费大量时间处理SQL语句。有的编写了简单的SQL,有的为非常复杂的业务逻辑SQL绞尽脑汁。那我想在这里问你一个简单的问题:你知道SQl语句的查询顺序是什么吗?当我第一次看到这个问题的时候,我的心是这样的。我写过无数的SQL查询语句,其中有一些非常复杂。还看不够吗??但事实是,我仍然很难准确地说出它的顺序。好了,不开玩笑了,我们先来看看SELECT语句的完整语法:1.SELECT2.DISTINCT3.FROM4.JOIN5.ON6.WHERE7??.GROUPBY8.HAVING9.ORDERBY10.LIMIT但是执行顺序如下FROM<表名>#CartesianproductON#过滤virtualtableofCartesianproductJOIN#指定join,用于在on之后往虚表中添加数据,比如leftjoin会把left的剩余数据转过来table添加到虚表中WHERE#过滤上面的虚表GROUPBY<分组条件>#Group#用来判断having子句,这种聚合函数是写的having在having判断中#聚合过滤分组结果SELECT#返回的单列必须在groupby子句中,聚合函数除外DISTINCT#重复数据删除ORDERBY<排序条件>#排序LIMIT<行数限制>其实SQL引擎在执行上面每一步的时候,都会在内存中形成一个虚表,然后对虚表进行后续操作,释放无用虚表的内存等等。具体过程如下:(后面的“VT”表示→虚表virtual)from:select*fromtable_1,table_2;与select*fromtable_1jointable_2的结果一致;both表示求笛卡尔积;用于直接计算表的两个笛卡尔积得到虚表VT1,这是所有select语句执行的第一个操作,其他操作都在这张表上进行,即from操作完成的内容on:FilterqualifiedVT1表中的数据,组成VT2表;join:将join类型的数据添加到VT2表中,例如leftjoin会将左表剩余数据添加到虚表VT2中,形成VT3表;如果表数大于2,则重复1-3步;其中:进行筛选,(不能使用聚合函数)得到VT4表;groupby:将VT4表分组得到VT5表;后处理语句,如select、having,使用的列必须包含在groupby条件中,如果没有聚合函数,则需要使用聚合函数;having:过滤分组数据得到VT6表;select:返回列得到VT7表;distinct:用它去重得到VT8表;orderby:用于排序得到VT9表;limit:返回需要的行数,得到VT10;需要注意的是:在groupby条件下,每一列必须是有效列,不能是聚合函数;null值也会作为一个组返回;除聚合函数外,select子句中的列必须在groupby条件中;上面告诉我们查询将返回什么,它也回答了以下问题:我可以在GRROUPBY之后使用WHERE吗?(不是,GROUPBY是在AfterWHERE!)窗口函数返回的结果可以过滤吗?(不是,窗口函数在SELECT语句中,而SELECT在WHERE和GROUPBY之后)是否可以根据GROUPBY中的东西进行ORDERBY?(是的,ORDERBY基本都是最后执行的,所以ORDERBY基于什么都可以)LIMIT是什么时候执行的?(在最后!)但是,数据库引擎不一定严格按照这个顺序执行SQL查询,因为为了更快的执行查询,他们会做一些优化,这些问题下面会解释↓↓↓SQL中的别名会影响SQL的执行顺序吗?如下SQL所示:SELECTCONCAT(first_name,'',last_name)ASfull_name,count(*)FROMtableGROUPBYfull_name从这条语句来看,GROUPBY好像是在SELECT之后执行的,因为它引用了SELECT中的别名。但实际上不一定非要这样,数据库引擎会这样重写查询:SELECTCONCAT(first_name,'',last_name)ASfull_name,count(*)FROMtableGROUPBYCONCAT(first_name,'',last_name)所以,BY还是先执行。另外,数据库引擎也会做一系列的检查,以确保SELECT和GROUPBY中的东西是有效的,所以在生成执行计划之前会对查询做一个整体的检查。数据库可能不会以正常顺序执行查询(优化)。在实践中,数据库可能不会按照JOIN、WHERE、GROUPBY的顺序执行查询,因为它们会进行一系列的优化,打乱执行顺序,让查询执行得更快,只要查询结果是没有改变。这个查询说明了为什么查询需要以不同的顺序执行:SELECT*FROMdeptdLEFTJOINstudentsONd.student_id=s.idWHEREs.name='WolfKing'如果您只需要查找名字为WolfKing的学生的信息,那么不需要比较两张表所有的数据都是左连接,在连接前进行过滤,这样查询会快很多,而且对于这个查询,先进行过滤不会改变查询结果。好吧。今天就到这里吧,我会继续分享我的所学所想,希望我们一起走在成功的路上!