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
繁體地址,請注明出處:http://hk.pswp.cn/news/908096.shtml
英文地址,請注明出處:http://en.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;…