MySQL中SELECT查询的执行顺序

MySQL中SELECT查询的执行顺序

在日常的数据库开发中,我们经常会写各种复杂的SELECT查询语句。然而,很多开发者对于MySQL实际执行这些查询的顺序并不完全了解。理解查询的执行顺序不仅有助于编写更高效的SQL语句,还能帮助我们更好地优化查询性能和避免常见的错误。

一、SELECT语句的书写顺序 vs 执行顺序

首先,让我们明确一个重要概念:SQL语句的书写顺序和实际执行顺序是不同的

书写顺序

SELECT DISTINCT column_list
FROM table_list
JOIN table ON join_condition
WHERE where_condition
GROUP BY column_list
HAVING having_condition
ORDER BY column_list
LIMIT count OFFSET offset

实际执行顺序

FROM -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY -> LIMIT

二、详解各步骤的执行顺序

让我们通过一个具体的例子来深入理解每个步骤:

SELECT DISTINCT d.dept_name,COUNT(e.emp_id) as emp_count,AVG(e.salary) as avg_salary
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
WHERE e.hire_date >= '2020-01-01'
GROUP BY d.dept_name
HAVING COUNT(e.emp_id) > 5
ORDER BY avg_salary DESC
LIMIT 10;

1. FROM 子句

执行顺序:第一步

MySQL首先确定数据来源,从指定的表中读取所有数据。

FROM employees e

此时会创建一个虚拟表VT1,包含employees表的所有行。

2. JOIN 子句

执行顺序:第二步

如果有JOIN操作,MySQL会根据连接条件合并表。

INNER JOIN departments d ON e.dept_id = d.dept_id
  • 生成笛卡尔积
  • 应用ON条件进行过滤
  • 根据JOIN类型(INNER/LEFT/RIGHT)决定保留哪些行
  • 生成虚拟表VT2

3. WHERE 子句

执行顺序:第三步

对JOIN后的结果集进行条件过滤。

WHERE e.hire_date >= '2020-01-01'

注意:WHERE子句不能使用聚合函数,因为此时还没有进行分组。生成虚拟表VT3。

4. GROUP BY 子句

执行顺序:第四步

按指定列对数据进行分组。

GROUP BY d.dept_name
  • 将VT3中的数据按dept_name分组
  • 每个分组变成结果集中的一行
  • 生成虚拟表VT4

5. HAVING 子句

执行顺序:第五步

对分组后的数据进行过滤。

HAVING COUNT(e.emp_id) > 5
  • HAVING可以使用聚合函数
  • 只保留员工数大于5的部门
  • 生成虚拟表VT5

6. SELECT 子句

执行顺序:第六步

选择要返回的列,执行表达式计算。

SELECT d.dept_name,COUNT(e.emp_id) as emp_count,AVG(e.salary) as avg_salary
  • 计算聚合函数
  • 执行表达式
  • 应用列别名
  • 生成虚拟表VT6

7. DISTINCT 子句

执行顺序:第七步

去除重复的行。

SELECT DISTINCT ...

生成虚拟表VT7。

8. ORDER BY 子句

执行顺序:第八步

对结果集进行排序。

ORDER BY avg_salary DESC
  • 可以使用SELECT中定义的别名
  • 可以使用未在SELECT中出现的列(如果该列在分组中)
  • 生成虚拟表VT8

9. LIMIT 子句

执行顺序:第九步

限制返回的行数。

LIMIT 10

最终返回前10条记录。

三、理解执行顺序的重要性

1. 别名的使用限制

由于执行顺序的原因,列别名在不同位置的可用性不同:

-- 错误示例:WHERE中不能使用SELECT定义的别名
SELECT salary * 12 as annual_salary
FROM employees
WHERE annual_salary > 50000;  -- 错误!-- 正确示例:
SELECT salary * 12 as annual_salary
FROM employees
WHERE salary * 12 > 50000;-- 或者使用子查询
SELECT * FROM (SELECT salary * 12 as annual_salaryFROM employees
) t
WHERE annual_salary > 50000;

2. WHERE vs HAVING

理解执行顺序可以帮助我们正确使用WHERE和HAVING:

-- WHERE:过滤行(分组前)
-- HAVING:过滤组(分组后)-- 错误:WHERE中使用聚合函数
SELECT dept_id, AVG(salary)
FROM employees
WHERE AVG(salary) > 5000  -- 错误!
GROUP BY dept_id;-- 正确:HAVING中使用聚合函数
SELECT dept_id, AVG(salary)
FROM employees
GROUP BY dept_id
HAVING AVG(salary) > 5000;-- 性能优化:尽可能使用WHERE
SELECT dept_id, AVG(salary)
FROM employees
WHERE salary > 3000  -- 先过滤,减少分组的数据量
GROUP BY dept_id
HAVING AVG(salary) > 5000;

3. JOIN的优化

理解JOIN在WHERE之前执行,可以帮助我们优化查询:

-- 低效:先JOIN所有数据,再WHERE过滤
SELECT *
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id
WHERE o.order_date >= '2024-01-01';-- 高效:在JOIN条件中尽早过滤
SELECT *
FROM orders o
INNER JOIN customers c ON o.customer_id = c.customer_id AND o.order_date >= '2024-01-01';

四、特殊情况和注意事项

1. 子查询的执行顺序

子查询的执行时机取决于其类型:

-- 非相关子查询:先执行子查询
SELECT * 
FROM employees 
WHERE dept_id IN (SELECT dept_id FROM departments WHERE location = 'Beijing'
);-- 相关子查询:对外查询的每一行执行一次
SELECT e1.* 
FROM employees e1
WHERE salary > (SELECT AVG(salary) FROM employees e2 WHERE e2.dept_id = e1.dept_id
);

2. UNION的执行顺序

(SELECT name FROM employees WHERE dept_id = 1)
UNION
(SELECT name FROM employees WHERE dept_id = 2)
ORDER BY name;
  • 先执行各个SELECT
  • 然后合并结果(去重)
  • 最后应用ORDER BY

3. 窗口函数的执行顺序

窗口函数在SELECT阶段执行,但在DISTINCT之前:

SELECT DISTINCTdept_id,salary,ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) as rn
FROM employees
WHERE hire_date >= '2020-01-01';

执行顺序:FROM -> WHERE -> SELECT(包括窗口函数) -> DISTINCT

五、性能优化建议

基于执行顺序的理解,我们可以得出以下优化建议:

1. 尽早过滤数据

-- 在WHERE中过滤,而不是HAVING
-- 在JOIN条件中过滤,而不是WHERE

2. 合理使用索引

-- 为WHERE、JOIN、ORDER BY涉及的列创建索引
CREATE INDEX idx_hire_date ON employees(hire_date);
CREATE INDEX idx_dept_id ON employees(dept_id);

3. 避免在WHERE中使用函数

-- 不好
WHERE YEAR(hire_date) = 2024-- 好
WHERE hire_date >= '2024-01-01' AND hire_date < '2025-01-01'

4. 使用EXPLAIN分析执行计划

EXPLAIN SELECT ... ;

六、常见误区总结

  1. 误区:认为SQL按书写顺序执行 事实:执行顺序是固定的,与书写顺序不同
  2. 误区:WHERE和HAVING可以互换使用 事实:WHERE过滤行,HAVING过滤组,执行时机不同
  3. 误区:SELECT中定义的别名可以在WHERE中使用 事实:WHERE在SELECT之前执行,无法使用别名
  4. 误区:ORDER BY总是最后执行 事实:如果有LIMIT,ORDER BY在LIMIT之前执行

结语

深入理解MySQL SELECT查询的执行顺序是编写高效SQL的基础。通过掌握这些知识,我们可以:

  • 避免常见的SQL错误
  • 编写更高效的查询
  • 更好地进行性能优化
  • 理解查询结果的生成过程

记住核心执行顺序:FROM -> JOIN -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> ORDER BY -> LIMIT

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/908096.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

es 的字段类型(text和keyword)

Text 当一个字段是要被全文检索时&#xff0c;比如 Email 内容、产品描述&#xff0c;这些字段应该使用 text 类型。设置 text 类型以后&#xff0c;字段内容会被分析&#xff0c;在生成倒排索引之前&#xff0c;字符串会被分析器分词。text类型的字段不用于排序&#xff0c;很…

MySQL安装及启用详细教程(Windows版)

MySQL安装及启用详细教程&#xff08;Windows版&#xff09; &#x1f4cb; 概述 本文档将详细介绍MySQL数据库在Windows系统下的下载、安装、配置和启用过程。 &#x1f4e5; MySQL下载 官方下载地址 官方网站: https://dev.mysql.com/downloads/社区版本: https://dev.my…

Linux下使用nmcli连接网络

Linux下使用nmcli连接网络 介绍 在使用ubuntu系统的时候&#xff0c;有时候不方便使用桌面&#xff0c;使用ssh远程连接&#xff0c;可能需要使用nmcli命令来连接网络。本文将介绍如何使用nmcli命令连接网络。nmcli 是 NetworkManager 的命令行工具&#xff0c;用于管理网络连…

Python----循环神经网络(BiLSTM:双向长短时记忆网络)

一、LSTM 与 BiLSTM对比 1.1、LSTM LSTM&#xff08;长短期记忆网络&#xff09; 是一种改进的循环神经网络&#xff08;RNN&#xff09;&#xff0c;专门解决传统RNN难以学习长期依赖的问题。它通过遗忘门、输入门和输出门来控制信息的流动&#xff0c;保留重要信息并丢弃无关…

U盘挂载Linux

在 只能使用 Telnet 的情况下&#xff0c;如果希望通过 U盘 传输文件到 Linux 系统&#xff0c;可以按照以下步骤操作&#xff1a; &#x1f4cc; 前提条件 U盘已插入 Linux 主机的 USB 接口。Linux 主机支持自动挂载 U盘&#xff08;大多数现代发行版默认支持&#xff09;。T…

QuickBASIC QB64 支持 64 位系统和跨平台Linux/MAC OS

QuickBASIC 的现代继任者 QB64 已发展成为一个功能强大的开源项目&#xff0c;支持 64 位系统和跨平台开发。以下是详细介绍&#xff1a; 项目首页 - QB64pe:The QB64 Phoenix Edition Repository - GitCode https://gitcode.com/gh_mirrors/qb/QB64pe 1. QB64 概述 官网&am…

【C++高级主题】命令空间(五):类、命名空间和作用域

目录 一、实参相关的查找&#xff08;ADL&#xff09;&#xff1a;函数调用的 “智能搜索” 1.1 ADL 的核心规则 1.2 ADL 的触发条件 1.3 ADL 的典型应用场景 1.4 ADL 的潜在风险与规避 二、隐式友元声明&#xff1a;类与命名空间的 “私密通道” 2.1 友元声明的基本规则…

免费开源Umi-OCR,离线使用,批量精准!

Umi-OCR&#xff08;Windows端&#xff09; Umi-OCR 是一款在 GitHub 上开源的免费 OCR 识别软件&#xff0c;它最大的亮点就是免费、开源、支持批量处理&#xff0c;而且识别准确度很高。这款软件不需要联网就能用&#xff0c;非常值得推荐&#xff01; 在 OCR 识别功能方面&…

深入剖析 Docker 容器化原理与实战应用,开启技术新征程!

文章目录 前言一、为什么 是Docker &#xff1f;二、Docker 容器化原理分析2.1 镜像&#xff08;Image&#xff09;2.2 容器&#xff08;Container&#xff09;2.3 仓库&#xff08;Registry&#xff09; 三、Docker 容器化实践3.1 Docker安装3.2 创建一个 Docker 镜像3.3 运行…

黑马程序员TypeScript课程笔记—class篇

class的基本使用 class的构造函数&#xff08;实现实例属性的初始化&#xff09; 在使用构造函数的时候&#xff0c;小括号的后面不要指定类型&#xff0c;否则就会报错&#xff0c;因为构造函数没有返回值 class实例方法 class继承&#xff08;extends&#xff09; class继承…

PDF.js无法显示数字签名

问题 pdfjs加载pdf文件时无法显示数字签名 PDF.js 从 v2.9.359 版本开始正式支持数字签名的渲染与显示&#xff0c;此前版本需通过修改源代码实现基础兼容。 建议升级pdfjs组件大于等于v2.9.359 pdfjs历史版本&#xff1a;https://github.com/mozilla/pdf.js/releases pdfjs…

解决VS Code误报Java问题的终极方法

使用vscode写java&#xff0c;发现很多Problems&#xff0c;如下图&#xff0c;实际上并没有问题&#xff0c;是误报&#xff0c;怎么解决&#xff1f; 解决方案&#xff1a;disable下面这个插件&#xff0c;它和vscode-java插件冲突了导致。

【WPF】从普通 ItemsControl 到支持筛选的 ItemsControl:深入掌握 CollectionViewSource 用法

✨ 从普通 ItemsControl 到支持筛选的 ItemsControl&#xff1a;深入掌握 CollectionViewSource 用法 在日常 WPF 开发中&#xff0c;我们经常需要对数据进行筛选、排序、分组等操作&#xff0c;而原生的 ItemsControl 并不直接支持这些功能。本文将介绍如何通过 CollectionVi…

Mybatis Plus JSqlParser解析sql语句及JSqlParser安装步骤

MyBatis Plus与JSqlParser&#xff1a;SQL语句解析与实战指南 在现代Java开发中&#xff0c;SQL解析和动态SQL生成是数据库操作中不可或缺的一部分。MyBatis Plus作为MyBatis的增强工具&#xff0c;通过JSqlParser库实现了对SQL语句的深度解析和修改能力。本文将详细介绍如何在…

学习路之PHP--easyswoole使用视图和模板

学习路之PHP--easyswoole使用视图和模板 一、安装依赖插件二、 实现渲染引擎三、注册渲染引擎四、测试调用写的模板五、优化六、最后补充 一、安装依赖插件 composer require easyswoole/template:1.1.* composer require topthink/think-template相关版本&#xff1a; "…

设计模式——享元设计模式(结构型)

摘要 享元设计模式是一种结构型设计模式&#xff0c;旨在通过共享对象减少内存占用和提升性能。其核心思想是将对象状态分为内部状态&#xff08;可共享&#xff09;和外部状态&#xff08;不可共享&#xff09;&#xff0c;并通过享元工厂管理共享对象池。享元模式包含抽象享…

互联网大厂Java求职面试:云原生微服务架构设计与AI大模型集成实战

互联网大厂Java求职面试&#xff1a;云原生微服务架构设计与AI大模型集成实战 面试场景设定 人物设定&#xff1a; 李明&#xff08;技术总监&#xff09;&#xff1a;拥有15年分布式系统架构经验&#xff0c;主导过多个亿级用户系统的重构&#xff0c;对云原生和AI融合有深…

nginx+tomcat动静分离、负载均衡

一、理论 nginx用于处理静态页面以及做调度器&#xff0c;tomcat用于处理动态页面 lvs&#xff08;四层&#xff09; 轮询&#xff08;rr&#xff09; 加权轮询&#xff08;wrr&#xff09; 最小连接&#xff08;lc&#xff09; 加权最小连接&#xff08;wlc&#xff09; ngi…

什么是AI芯片?

首先&#xff0c;我们要了解一下&#xff1a;什么是芯片&#xff1f;芯片的本质就是在半导体衬底上制作能实现一系列特定功能的集成电路。 其次&#xff0c;来看一下AI的概念。AI是研究如何使计算机能够模拟和执行人类智能任务的科学和技术领域&#xff0c;致力于开发能够感知…

PostgreSQL数据库配置SSL操作说明书

背景&#xff1a; 因为postgresql或者mysql目前通过docker安装&#xff0c;只需要输入主机IP、用户名、密码即可访问成功&#xff0c;这样其实是不安全的&#xff0c;可能会通过一些手段获取到用户名密码导致数据被窃取。而ES、kafka等也是通过用户名/密码方式连接&#xff0c;…