当前位置: 首页 > news >正文

SQL 查询语句总是先执行 SELECT?你们都错了

很多 SQL 查询都是以 SELECT 开始的。不过,最近我跟别人解释什么是窗口函数,我在网上搜索”是否可以对窗口函数返回的结果进行过滤“这个问题,得出的结论是”窗口函数必须在 WHERE 和 GROUP BY 之后,所以不能”。于是我又想到了另一个问题:SQL 查询的执行顺序是怎样的?

这个问题好像应该很好回答,毕竟自己已经写了上万个 SQL 查询了,有一些还很复杂。但事实是,我仍然很难确切地说出它的顺序是怎样的。

SQL 查询的执行顺序  

于是我研究了一下,发现顺序大概是这样的。SELECT 并不是最先执行的,而是在第五个。

这张图回答了以下这些问题  

这张图与 SQL 查询的语义有关,让你知道一个查询会返回什么,并回答了以下这些问题:

  • 可以在 GRROUP BY 之后使用 WHERE 吗?(不行,WHERE 是在 GROUP BY 之前!)

  • 可以对窗口函数返回的结果进行过滤吗?(不行,窗口函数是 SELECT 语句里,而 SELECT 是在 WHERE 和 GROUP BY 之后)

  • 可以基于 GROUP BY 里的东西进行 ORDER BY 吗?(可以,ORDER BY 基本上是在最后执行的,所以可以基于任何东西进行 ORDER BY)

  • LIMIT 是在什么时候执行?(在最后!)

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

所以:

  • 如果你想要知道一个查询语句是否合法,或者想要知道一个查询语句会返回什么,可以参考这张图;

  • 在涉及查询性能或者与索引有关的东西时,这张图就不适用了。

混合因素:列别名  

有很多 SQL 实现允许你使用这样的语法:

SELECT CONCAT(first_name, ' ', last_name) AS full_name, count(*)
FROM table
GROUP BY full_name

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

SELECT CONCAT(first_name, ' ', last_name) AS full_name, count(*)
FROM table
GROUP BY CONCAT(first_name, ' ', last_name)

这样 GROUP BY 仍然先执行。

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

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

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

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

SELECT * FROM
owners LEFT JOIN cats ON owners.id = cats.owner
WHERE cats.name = 'mr darcy'

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

数据库引擎还会做出其他很多优化,按照不同的顺序执行查询,不过我并不是这方面的专家,所以这里就不多说了。

LINQ 的查询以 FROM 开头  

LINQ(C# 和 VB.NET 中的查询语法)是按照 FROM...WHERE...SELECT 的顺序来的。这里有一个 LINQ 查询例子:

var teenAgerStudent = from s in studentList
                      where s.Age > 12 && s.Age < 20
                      select s;

pandas 中的查询也基本上是这样的,不过你不一定要按照这个顺序。我通常会像下面这样写 pandas 代码:

df = thing1.join(thing2)      # JOIN
df = df[df.created_at > 1000] # WHERE
df = df.groupby('something', num_yes = ('yes', 'sum')) # GROUP BY
df = df[df.num_yes > 2]       # HAVING, 对 GROUP BY 结果进行过滤
df = df[['num_yes', 'something1', 'something']] # SELECT, 选择要显示的列
df.sort_values('sometthing', ascending=True)[:30] # ORDER BY 和 LIMIT
df[:30]

这样写并不是因为 pandas 规定了这些规则,而是按照 JOIN/WHERE/GROUP BY/HAVING 这样的顺序来写代码会更有意义些。不过我经常会先写 WHERE 来改进性能,而且我想大多数数据库引擎也会这么做。

R 语言里的 dplyr 也允许开发人员使用不同的语法编写 SQL 查询语句,用来查询 Postgre、MySQL 和 SQLite。

原文链接:

https://jvns.ca/blog/2019/10/03/sql-queries-don-t-start-with-select/

精彩回顾

♡ 程序员究竟能干多少年?

♡ 互联网公司各岗位真实工作内容起底

♡ 一次尴尬的采访和程序员的传奇脑洞!

♡ 天一冷,程序员都穿上格子衫

♡ 史上最真实的行业鄙视链曝光

♡ IT公司老板落水,各部门员工怎么救

♡ 宿命之战:程序员VS产品经理

♡ 作为一个前端,可以如何机智地弄坏一台电脑?

♡ 程序员跟产品经理打起来了,这是一个需求引发的血案...

♡ 后端说,你个前端不会用 headers吧,我怒了!

♡ 有个厉害的程序员女朋友是什么体验?

♡ 多年来,程序员经常加班的真相终于揭开了…

相关文章:

  • 看完知乎轮子哥的编程之路,我只想说,收下我的膝盖。。。
  • 巧用Java8中的Stream,让集合操作6到飞起!!!
  • 每个项目组大概就是这样吧
  • 两万字深度介绍分布式系统原理,一文入魂
  • 两种类型的程序员
  • 一张图了解Linux
  • 为什么说重启能解决90%的问题?
  • C 和 C++ 父子关系
  • 我已经可以想象,疫情结束后全国男生会……
  • 完美的递归函数视觉表示
  • 真正的黑客键盘
  • 复旦研究生怒怼华为:2w月薪是侮辱价!
  • 接手遗留代码后,我越来越强了
  • 灵活运用JS开发技巧
  • 如何画好架构图
  • [js高手之路]搞清楚面向对象,必须要理解对象在创建过程中的内存表示
  • Android 架构优化~MVP 架构改造
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • happypack两次报错的问题
  • JavaScript服务器推送技术之 WebSocket
  • Java知识点总结(JavaIO-打印流)
  • Spring Boot快速入门(一):Hello Spring Boot
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Terraform入门 - 1. 安装Terraform
  • vue中实现单选
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 规范化安全开发 KOA 手脚架
  • 前嗅ForeSpider中数据浏览界面介绍
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 自定义函数
  • ​如何防止网络攻击?
  • !$boo在php中什么意思,php前戏
  • (笔试题)合法字符串
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (万字长文)Spring的核心知识尽揽其中
  • *上位机的定义
  • .net core 控制台应用程序读取配置文件app.config
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .net图片验证码生成、点击刷新及验证输入是否正确
  • .net中生成excel后调整宽度
  • .php结尾的域名,【php】php正则截取url中域名后的内容
  • @Transactional注解下,循环取序列的值,但得到的值都相同的问题
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [ 数据结构 - C++]红黑树RBTree
  • [14]内置对象
  • [2016.7 Day.4] T1 游戏 [正解:二分图 偏解:奇葩贪心+模拟?(不知如何称呼不过居然比std还快)]
  • [AI]文心一言爆火的同时,ChatGPT带来了这么多的开源项目你了解吗
  • [AS3]URLLoader+URLRequest+JPGEncoder实现BitmapData图片数据保存
  • [bzoj1912]异象石(set)
  • [CISCN2019 华东南赛区]Web11
  • [COGS 622] [NOIP2011] 玛雅游戏 模拟
  • [C语言]一维数组二维数组的大小
  • [leetcode 189][轮转数组]