很多 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。

作者:Julia Evans,译者:无明,

原文:https://dwz.cn/J4jxxAkQ

- END -
推荐阅读:

你确定 SQL 查询都是以 SELECT 开始的?的更多相关文章

  1. SQL 查询并不是从 SELECT 开始的

    原文地址:SQL queries don't start with SELECT 原文作者:Julia Evans(已授权) 译者 & 校正:HelloGitHub-小熊熊 & 卤蛋 ...

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

    SELECT语句中子句的顺序.SELECT语句中使用时必须遵循的次序. 经过一段时间的学习,我们知道了SELECT语句超简版的语法如下: SELECT 字段名 FROM 表名 后来,我们又陆续学习了W ...

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

    很多 SQL 查询都是以 SELECT 开始的.不过,最近我跟别人解释什么是窗口函数,我在网上搜索"是否可以对窗口函数返回的结果进行过滤"这个问题,得出的结论是"窗口函数 ...

  4. [转]sql语句中出现笛卡尔乘积 SQL查询入门篇

    本篇文章中,主要说明SQL中的各种连接以及使用范围,以及更进一步的解释关系代数法和关系演算法对在同一条查询的不同思路. 多表连接简介 在关系数据库中,一个查询往往会涉及多个表,因为很少有数据库只有一个 ...

  5. sql语句中出现笛卡尔乘积 SQL查询入门篇

    2014-12-29  凡尘工作室   阅 34985  转 95 本篇文章中,主要说明SQL中的各种连接以及使用范围,以及更进一步的解释关系代数法和关系演算法对在同一条查询的不同思路. 多表连接简介 ...

  6. SQL查询几种的区别。

    最近看了几篇SQL查询的文章做一下总结哦,大概简记如下: SQL查询的实质是,是指从数据库中取得数据的子集,可以先取列子集,然后再取符合条件的行子集. 1.单表查询: SELECT [Name] ,[ ...

  7. SQL查询数据总结

    SQL查询数据 完整语法 Select [select选项] 字段列表[字段别名]/* from 数据源 [where条件子句] [group by子句] [having子句] [order by子句 ...

  8. 一个SQL查询出每门课程的成绩都大于80的学生姓名

    name   kecheng    fenshu 张三     语文     81 张三     数学     75 李四     语文     76 李四     数学     90 王五     ...

  9. SQL Fundamentals: 子查询 || WHERE,HAVING,FROM,SELECT子句中使用子查询,WITH子句

    SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5 ...

随机推荐

  1. CSS3的2D 转换——旋转,缩放,translate(),skew(),matrix()

    2D转换方法:在平面对元素进行旋转,缩放,移动,拉伸. ㈠浏览器支持 ⑴2D转换效果有以下的浏览器支持:   ⑵在编辑代码的时候要注明用哪种浏览器打开,在前面加上前缀,下面是编辑器的简写形式,以及前缀 ...

  2. codevs 1009 产生数x

                         题目描述 Description 给出一个整数 n(n<10^30) 和 k 个变换规则(k<=15). 规则: 一位数可变换成另一个一位数: 规 ...

  3. 后盾网lavarel视频项目---lavarel多表关联一对多操作实例

    后盾网lavarel视频项目---lavarel多表关联一对多操作实例 一.总结 一句话总结: 1.一对多中多那个部分的数据前端通过json弄到服务器 2.所有通过一操作多的时候,都要用上模型中定义的 ...

  4. Laravel 在构造方法中使用session

  5. synchronized 读写同步

    synchronized 读写同步 这是一道面试题,很多人也遇到了. 要求:1.读-读 不用线程同步.2.读-写 要求线程同步,写的时候不能读.3.写-写同步.写的时候不能写. java lock读写 ...

  6. 描述一下 Intent 和 IntentFilter?

    Android 中通过 Intent 对象来表示一条消息,一个 Intent 对象不仅包含有这个消息的目的地,还可以包含消息的内容,这好比一封 Email,其中不仅应该包含收件地址,还可以包含具体的内 ...

  7. Linux常用命令:修改文件权限chmod 754/744

    常用命令:chmod 777  文件或目录 chmod  777 /etc/squid 运行命令后,squid文件夹(目录)的权限就被修改为777(可读可写可执行). Linux系统中,每个用户的角色 ...

  8. 重复执行用例(pytest-repeat)

    前言 平常在做功能测试的时候,经常会遇到某个模块不稳定,偶然会出现一些bug,对于这种问题我们会针对此用例反复执行多次,最终复现出问题来.自动化运行用例时候,也会出现偶然的bug,可以针对单个用例,或 ...

  9. Oracle 笔记(一)

    Oracle基本理论 l  主流数据库 微软公司:SQL Server  ACCESS IBM公司:DB2  infomix Oracle公司:Oracle  MySQL(AB公司) 小型数据库 AC ...

  10. Spring----EJB

    EJB 是 Java EE 诸多规范之一,而 Spring 仅仅是一个框架并不是 Java EE. EJB 是百分百纯血统的 JCP 官方规范,而 Spring 是民间发起的框架. EJB 必须运行在 ...