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

SQL查询不从Select开始

时间:2023-03-12 14:00:56 科技观察

本文转载自微信公众号「HelloGitHub」,作者HelloGitHub。转载本文请联系HelloGitHub公众号。在日常使用中,编写SQL查询命令从SELECT开始(注意:本文只讨论SELECT查询,不讨论insert或其他SQL命令)。昨天想到了一个问题:是否可以通过WHERE、HAVING或者其他方法来过滤窗口函数的执行结果?经过一番摸索,最后得出的结论是否定的,因为窗口函数必须在WHERE和GROUPBY之后运行。然而,这也引申出一个更大的问题——SQL查询的执行顺序是什么?SQL查询的执行顺序我特地查了文档。SQL查询的执行顺序如下:如果不喜欢上面花花绿绿的图片,还可以看下面的文字:FROM/JOIN/ONWHEREGROUPBYHAVINGSELECT(窗口函数在这一步执行)ORDERBYLIMIT上图可以解答你的以下疑惑:上图是SQL查询的语义描述。看懂这张图,你就可以快速判断给定的SQL查询会返回什么结果,你就可以轻松回答下面的问题:WHERE可以过滤GROUPBY的结果吗?(不能!因为WHERE在GROUPBY执行之前)窗口函数的执行结果可以过滤吗?(不能!因为窗口函数是在SELECT这一步执行的,而这一步是在WHERE和GROUPBY之后)GROUPBY的结果是否可以进行ORDERBY操作?(是的!ORDERBY基本上是最后一步,所以你可以对任何操作的执行结果执行ORDERBY)LIMIT是在哪一步执行的?(最后一步!)即便如此,数据库引擎实际上并没有按照这个顺序运行查询,因为它们还进行了一系列优化以提高查询速度。所以:当你想了解查询语句的有效性,或者想了解为什么会返回这样的查询结果时,你可以尝试用这张图来解释;但是,使用此图无法解释查询性能或与索引相关的问题。它们涉及更多变量,因此更复杂。1、最容易混淆的:列别名如:将名字和姓氏关联起来,并分组。SQL语法允许这样写:SELECTCONCAT(first_name,'',last_name)ASfull_name,count(*)FROMtableGROUPBYfull_name上面的查询看起来是在SELECT之后执行GROUPBY,但实际上GROUPBY先执行,因为GROUPBY在SELECT中引用别名。数据库引擎可以将查询重写为:SELECT*FROMownersLEFTJOINcatsONowners.id=cats.ownerWHEREcats.name='mrdarcy'然后,先执行GR??OUPBY中的语句,再进行SELECT操作,所以上面的写法是可行的。另外,数据库引擎在查询开始运行之前肯定会进行一系列的检查以确保SELECT和GROUPBY的内容匹配,所以在制定执行计划之前必须对查询语句进行整体检查。二、查询并没有严格按照这个顺序运行(优化)实际上,数据库引擎并没有通过连接、过滤和分组来运行查询,因为它实现了一系列的优化来提高查询速度,比如重新排序(只要因为它不影响最终的返回结果)。下面用一个简单的例子来说明查询的执行顺序是如何影响查询性能的。SELECTCONCAT(first_name,'',last_name)ASfull_name,count(*)FROMtableGROUPBYfull_name如果您只需要查找3只名为“mrdarcy”的猫,则执行整个左连接并匹配两个表中的所有行的速度很慢。相反,在执行连接之前过滤名为“mrdarcy”的猫要快得多。在这种情况下,先进行过滤不会改变查询的结果!其实数据库引擎还实现了很多其他的优化,使得查询语句的执行顺序不同,这里就不一一列举了。3、查询语法不同LINQ(C#和VB.NET中的查询语法)按照FROM...WHERE...SELECT的顺序执行查询。以下是LINQ查询的示例:varteenAgerStudent=fromsinstudentListwheres.Age>12&&s.Age<20selects;Pandas(Python数据统计分析工具)基本上是这样工作的,虽然有时候不一定要严格按照下面的顺序写代码,但这也是一个好习惯:df=thing1.join(thing2)#likeaJOINdf=df[df.created_at>1000]#likeaWHEREdf=df.groupby('something',num_yes=('yes','sum'))#likeaGROUPBYdf=df[df.num_yes>2]#likeaHAVING,filteringontheresultofaGROUPBYdf=df[['num_yes','something1','something']]#pickthecolumnsIwanttodisplay,likeaSELECTdf.sort_values('something',ascending=True)[:30]#ORDERBYandLIMITdf[:30]这不是因为pandas的强制规定,而是它按照JOIN/WHERE/GROUPBY/HAVING的顺序写代码更有利于理解底层逻辑。(值得一提的是,你可以在JOIN之前执行WHERE以提高性能,大多数数据库引擎在实践中都是这样做的。)R中的dplyr(用于操作数据框的R语言包)还允许使用不同的语法来查询不同的SQL数据库,例如Postgres、MySQL和SQLite。最后发现这个SQL查询语句的执行顺序的时候,其实我很惊讶。通过探究SQL查询语句的执行顺序,弄清了之前遇到的问题。也希望这篇文章能够帮助更多人了解SQL的执行顺序,以及如何正确编写SQL查询语句。最后感谢作者授权:原文地址:SQL查询不以SELECT开头原作者:JuliaEvans(已授权)译者&校正:HelloGitHub-小熊&红烧蛋