Python 还能承担下一个时代的发展重任吗?Mojo 语言的横空出世对 AI 研发生态有什么影响? 了解详情
写点什么

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

  • 2019-10-21
  • 本文字数:1675 字

    阅读完需:约 5 分钟

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 tableGROUP BY full_name
复制代码


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


SELECT CONCAT(first_name, ' ', last_name) AS full_name, count(*)FROM tableGROUP BY CONCAT(first_name, ' ', last_name)
复制代码


这样 GROUP BY 仍然先执行。


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

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

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


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


SELECT * FROMowners LEFT JOIN cats ON owners.id = cats.ownerWHERE 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)      # JOINdf = df[df.created_at > 1000] # WHEREdf = df.groupby('something', num_yes = ('yes', 'sum')) # GROUP BYdf = df[df.num_yes > 2]       # HAVING, 对GROUP BY结果进行过滤df = df[['num_yes', 'something1', 'something']] # SELECT, 选择要显示的列df.sort_values('sometthing', ascending=True)[:30] # ORDER BY 和 LIMITdf[:30]
复制代码


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


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


原文链接:


SQL queries don’t start with SELECT


2019-10-21 17:343312

评论 1 条评论

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

那这里是先执行的where?
2021-04-15 17:36
回复
没有更多了
发现更多内容

数据库索引为什么使用B+树

hasWhere

Zookeeper在线迁移

阿骆麦迪

zookeeper 分布式 中间件 6月日更

科普 DeFi 中的闪电贷

hasWhere

Kubernetes手记(13)- 用户认证系统

雪雷

k8s 6月日更

django-task1 笔记之python基础

橙橙橙橙汁丶

django #python

servlet工作原理之tomcat篇

hasWhere

戏说前端 JavaScript 之『防抖节流』基础知识

编程三昧

JavaScript 大前端 防抖节流 函数节流 函数防抖

源码级别理解 Redis 持久化

蘑菇睡不着

Java redis Redis 协议

从金融街往事到全场景智慧金融未来

脑极体

期权的初步认识

Qien Z.

期权 6月日更

区块链场景化应用大有可为

CECBC

「SQL数据分析系列」5. 多表查询

数据与智能

数据库 sql 查询语句

MySQL基础之十四:事务

打工人!

MySQL 6月日更

深入了解Spring框架之WebMVC框架

邱学喆

spring webmvc HandlerMethod HandlerInterceptor

DeFi从入门到精通

hasWhere

相比买买买,我们更想在618聊一聊云厂商的能力象限价值几何

脑极体

全国首个“区块链+数字人民币”应用场景在雄安新区落地

CECBC

CSS实战 | 磁性页头和页脚的表格制作

devpoint

CSS 6月日更

Java中的关键字final

架构精进之路

Java 6月日更

内推学弟进了腾讯,看看他的标杆简历!

程序员鱼皮

Java 后端 简历 校招 秋招

Tomcat架构的认知

邱学喆

tomcat @WebServlet @WebFilter Manager

《原则》(十六)

Changing Lin

6月日更

沟通的方法:反向叙述

石云升

读书笔记 沟通 6月日更

【21-9】文件和文件夹

耳东@Erdong

PowerShell 6月日更

算法第零期开营仪式总结

IT蜗壳-Tango

6月日更

form-data和x-www-form-urlencoded

hasWhere

5分钟速读之Rust权威指南(二十三)Cargo

wzx

rust

网络攻防学习笔记 Day46

穿过生命散发芬芳

网络攻防 6月日更

图论环境配置出现的各种错误

容光

一个jvm线程占用多少操作系统内存

hasWhere

让区块链价值的属性之一“免信任”,更好的融入

CECBC

  • 扫码加入 InfoQ 开发者交流群
SQL查询语句总是先执行SELECT?你们都错了_语言 & 开发_Julia Evans_InfoQ精选文章