SQL查詢語句的執行順序

好的,我們來詳細講解一下 SQL 查詢語句的執行順序
很多人會誤以為 SQL 的執行順序就是我們寫的順序(SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY),但實際上,數據庫引擎在底層處理查詢時,遵循一個完全不同的邏輯順序。理解這個順序對于編寫高效、正確的 SQL 查詢至關重要。

一、核心執行順序(邏輯查詢處理順序)

這是 SQL 查詢在數據庫內部被處理的邏輯步驟。每一步都會產生一個虛擬表,作為下一步的輸入。
我們以一個完整的查詢為例:

SELECT DISTINCT column1, column2
FROM table1
JOIN table2 ON table1.id = table2.id
WHERE condition
GROUP BY column1
HAVING group_condition
ORDER BY column2 DESC
LIMIT n;

它的實際執行順序如下:

第 1 步:FROM / JOIN
  • 作用:確定需要查詢的數據來源。數據庫引擎首先會執行 FROM 子句,如果有關聯的表(JOIN),它會根據 ON 條件將這些表連接起來,形成一個大的虛擬表(VT1)。
  • 為什么是第一步:因為所有后續的操作(篩選、分組、排序)都必須基于一個完整的數據集。
第 2 步:WHERE
  • 作用:對 FROM 步驟生成的虛擬表(VT1)進行行級過濾。根據 WHERE 子句中的條件,移除不滿足條件的行,生成一個新的虛擬表(VT2)。
  • 關鍵點WHERE 子句在分組和聚合之前執行。因此,它不能使用聚合函數(如 COUNT(), SUM(), AVG())。如果你嘗試在 WHERE 中使用聚合函數,數據庫會報錯。
  • 性能提示:這是進行數據篩選最重要的環節,盡早過濾掉無用數據可以大大減少后續步驟的計算量。
第 3 步:GROUP BY
  • 作用:根據 GROUP BY 子句中指定的列,將 WHERE 步驟過濾后的虛擬表(VT2)中的數據進行分組。具有相同分組列值的行會被合并到一組,生成一個新的虛擬表(VT3)。
  • 結果:此時的虛擬表由多個“組”構成,每一組代表一個唯一的分組鍵值。
第 4 步:HAVING
  • 作用:對 GROUP BY 步驟生成的分組進行過濾。它類似于 WHERE,但作用于而不是單行。根據 HAVING 子句中的條件,移除不滿足條件的組,生成一個新的虛擬表(VT4)。
  • 關鍵點HAVING分組之后執行,因此它可以使用聚合函數(如 HAVING COUNT(*) > 5)。這是 HAVINGWHERE 最本質的區別。
第 5 步:SELECT
  • 作用:這是最容易被誤解的一步。直到這一步,數據庫才開始真正“選擇”需要返回的列。它會遍歷 HAVING 步驟生成的虛擬表(VT4),并只保留 SELECT 子句中明確指定的列(或表達式),生成一個新的虛擬表(VT5)。
  • 關鍵點
    • 別名生效:在 SELECT 步驟中定義的列別名(如 SELECT salary * 12 AS annual_salary),在這一步之后才生效。這就是為什么在 WHEREGROUP BY 中不能使用 SELECT 中定義的別名,但在 ORDER BY 中卻可以的原因。
    • 表達式計算:在 SELECT 中定義的表達式(如數學運算、函數調用)也是在這一步進行計算的。
第 6 步:DISTINCT
  • 作用:對 SELECT 步驟生成的虛擬表(VT5)進行去重。移除所有完全相同的行,生成一個新的虛擬表(VT6)。
  • 性能DISTINCT 操作通常需要排序或哈希,可能會消耗較多資源,應謹慎使用。
第 7 步:ORDER BY
  • 作用:對最終的結果集(DISTINCT 步驟后的虛擬表 VT6)進行排序。根據 ORDER BY 子句中指定的列和排序方式(ASCDESC)對行進行排序。
  • 關鍵點
    • 最后一步之一ORDER BY 是在幾乎所有數據處理完成后才執行的。
    • 可以使用別名:因為 ORDER BYSELECT 之后執行,所以它可以引用 SELECT 中定義的列別名。
第 8 步:LIMIT / OFFSET / TOP
  • 作用:這是整個查詢的最后一步。它從排序好的結果集中,限制返回的行數。
    • LIMIT n:返回前 n 行。
    • OFFSET m LIMIT n:跳過前 m 行,返回接下來的 n 行。
    • TOP n:返回前 n 行。
  • 性能提示LIMIT 通常在分頁查詢中使用。但請注意,如果查詢中包含了 ORDER BY,數據庫需要先對所有符合條件的數據進行排序,然后再應用 LIMIT,這在數據量很大時可能會很慢。

二、執行順序與書寫順序的對比

執行順序子句作用描述書寫順序
1FROM, JOIN確定數據源,連接表2
2WHERE過濾行(在分組前)3
3GROUP BY對行進行分組4
4HAVING過濾組(在分組后)5
5SELECT選擇列,計算表達式,定義別名1
6DISTINCT去重1 (在SELECT后)
7ORDER BY對最終結果排序6
8LIMIT限制返回的行數7

三、為什么理解執行順序很重要?(實例說明)

1. 為什么 WHERE 中不能用聚合函數,而 HAVING 可以?
-- 錯誤的寫法
SELECT department, COUNT(*) as emp_count
FROM employees
WHERE COUNT(*) > 5  -- 報錯!因為 WHERE 在 GROUP BY 之前執行,此時 COUNT(*) 還不存在
GROUP BY department;
-- 正確的寫法
SELECT department, COUNT(*) as emp_count
FROM employees
GROUP BY department  -- 先分組
HAVING COUNT(*) > 5; -- 再對組進行過濾
2. 為什么 ORDER BY 可以使用 SELECT 中的別名,而 WHERE 不可以?
-- 錯誤的寫法
SELECT first_name, salary * 12 AS annual_salary
FROM employees
WHERE annual_salary > 60000; -- 報錯!因為 WHERE 在 SELECT 之前執行,別名 'annual_salary' 還不存在
-- 正確的寫法
SELECT first_name, salary * 12 AS annual_salary
FROM employees
WHERE salary * 12 > 60000; -- 在 WHERE 中重復寫表達式
-- 或者,利用執行順序,在 ORDER BY 中使用別名
SELECT first_name, salary * 12 AS annual_salary
FROM employees
WHERE salary > 5000 -- 先用原始列過濾
ORDER BY annual_salary DESC; -- 再用別名排序(因為 ORDER BY 在 SELECT 之后)

總結

記住這個核心順序:FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT
將 SQL 的執行順序想象成一條流水線,數據從源頭(FROM)開始,經過一道道工序(WHERE, GROUP BY 等)的加工和篩選,最終形成我們想要的產品(結果集)。理解了這個流程,你就能更清晰地思考問題,寫出邏輯正確、性能更優的 SQL 查詢。


SELECT 中的非聚合列必須出現在 GROUP BY 子句中,否則會報錯。

HAVING 子句用于過濾聚合函數的結果(如 SUM、COUNT、AVG 等)。
g.weight < 50 是對原始列的過濾,不屬于聚合條件,應該放在 WHERE 子句中。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/93866.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/93866.shtml
英文地址,請注明出處:http://en.pswp.cn/web/93866.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Android】OKHttp網絡請求原理和弱網優化

【Android】OKHttp網絡請求原理和弱網優化 1. OkHttp 網絡請求原理 OkHttp 的請求過程可以分為 四個關鍵階段&#xff1a; &#xff08;假設你是通過 OkHttpClient.newCall(request).enqueue(callback) 發的請求&#xff09; OkHttpClient│▼ Dispatcher (調度器)│▼ RealC…

概率論基礎教程第4章 隨機變量(四)

4.7 泊松隨機變量 定義 泊松隨機變量&#xff1a;如果一個取值于 $ 0, 1, 2, \ldots $ 的隨機變量對某一個 $ \lambda > 0 $&#xff0c;其分布列為&#xff1a; p(i)P{Xi}e?λλii!i0,1,2,?(7.1) \boxed{p(i) P\{X i\} e^{-\lambda} \frac{\lambda^i}{i!} \qquad i 0…

Unity高級開發:反射原理深入解析與實踐指南 C#

Unity高級開發&#xff1a;反射原理深入解析與實踐指南 在Unity游戲開發中&#xff0c;反射&#xff08;Reflection&#xff09; 是一項強大的元編程技術&#xff0c;它允許程序在運行時動態地獲取類型信息、創建對象和調用方法。根據Unity官方統計&#xff0c;超過78%的商業游…

任務五 推薦頁面功能開發

一、推薦頁面需求分析 由推薦頁面效果圖,可以看出,推薦頁面主要由頂部輪播圖和歌單列表頁面組成 二、推薦頁面輪播圖組件封裝 由于輪播圖,可能在項目多個地方用到,因此可以將輪播圖抽調成一個組件,然后各個頁面調用這個組件。 在開發輪播圖組件時,需要安裝better-scro…

【工具使用-Docker容器】構建自己的鏡像和容器

1. 鏡像和容器介紹 鏡像&#xff08;Image&#xff09;是一個只讀的模板&#xff0c;包含了運行某個應用所需的全部內容&#xff0c;比如&#xff1a; 操作系統&#xff08;比如 Ubuntu&#xff09;應用程序代碼運行環境&#xff08;如 Python、Java、Node.js 等&#xff09;庫…

Apache Shiro550 漏洞(CVE-2016-4437):原理剖析與實戰 SOP

在 Web 安全領域&#xff0c;反序列化漏洞一直是威脅等級極高的存在&#xff0c;而 Apache Shiro 框架中的 Shiro550 漏洞&#xff08;CVE-2016-4437&#xff09;&#xff0c;更是因利用門檻低、影響范圍廣&#xff0c;成為滲透測試中頻繁遇到的經典漏洞。本文將從 “原理拆解”…

安卓開發者自學鴻蒙開發3持久化/數據與UI綁定

AppStorage,PersistentStorage與StorageLink AppStorage是應用全局狀態管理器,數據存儲于內存中,常見的如全局的黑暗模式,StorageLink是用來綁定AppStorage的鍵到ui上的工具,省去了用戶手寫代碼的無聊過程,PersistentStorage可以綁定AppStorage的鍵,自動持久化到磁盤,同時支持多…

GitHub宕機生存指南:從應急協作到高可用架構設計

GitHub宕機生存指南&#xff1a;從應急協作到高可用架構設計 摘要&#xff1a; GitHub作為全球開發者的協作中心&#xff0c;其服務穩定性至關重要。然而&#xff0c;任何在線服務都無法保證100%的可用性。本文深入探討了當GitHub意外宕機時&#xff0c;開發團隊應如何應對。我…

機器學習算法篇(十三)------詞向量轉化的算法思想詳解與基于詞向量轉換的文本數據處理的好評差評分類實戰(NPL基礎實戰)

目錄 一、詞向量原理介紹 (1). 詞向量的核心概念 (2). 傳統文本表示的局限性 1. 獨熱編碼&#xff08;One-Hot Encoding&#xff09; 2. 詞袋模型&#xff08;Bag of Words&#xff09; 3. TF-IDF (3). 詞向量的核心原理 (4). 主流詞向量模型 1. Word2Vec&#xff08;20…

JS自定義函數(2)

1. 變量的作用域全局變量定義&#xff1a;在函數外聲明的變量作用范圍&#xff1a;在整個JS文檔中生效生命周期&#xff1a;頁面關閉時銷毀局部變量定義&#xff1a;在函數內用 var 聲明的變量作用范圍&#xff1a;只能在函數內部使用生命周期&#xff1a;函數執行完畢時銷毀作…

【數據集】Argoverse 數據集:自動駕駛研究的強大基石

Argoverse數據集&#xff1a;自動駕駛研究的強大基石 在自動駕駛技術蓬勃發展的當下&#xff0c;高質量的數據集對于推動相關算法研究和模型訓練起著舉足輕重的作用。Argoverse 數據集便是其中的佼佼者&#xff0c;它為自動駕駛領域的眾多任務提供了豐富且優質的數據資源。 一、…

--- 哈希表和哈希沖突 ---

哈希&#xff08;散列&#xff09;方法是對插入的數據通過哈希函數計算出一個哈希地值&#xff0c;并將這個哈希地址作為儲存改數據的地址&#xff0c;這樣下次再查找這個數據時&#xff0c;只需要通過哈希函數再獲取到該地址然后直接去拿就好這樣就做到了不經過任何比較&#…

數學建模-評價類問題-優劣解距離法(TOPSIS)

1-AI帶你認識TOPSIS&#x1f4d8; 一、TOPSIS 方法簡介1. ??基本定義&#xff1a;????TOPSIS&#xff08;Technique for Order Preference by Similarity to an Ideal Solution&#xff09;??&#xff0c;中文通常稱為&#xff1a;???優劣解距離法?????逼近理想…

Go協程:從匯編視角揭秘實現奧秘

&#x1f680; Go協程&#xff1a;從匯編視角揭秘實現奧秘 #Go語言 #協程原理 #并發編程 #底層實現 引用&#xff1a; 關于 Go 協同程序&#xff08;Coroutines 協程&#xff09;、Go 匯編及一些注意事項。 &#x1f31f; 前言&#xff1a;重新定義并發編程范式 在當今高并發…

MySQL 事務(重點)

MySQL 這個東西注定是可能會被多個用戶/客戶端來同時訪問的&#xff0c;這是肯定的&#xff0c;MySQL 中存放的都是數據&#xff0c;數據可能有一個上層線程在用&#xff0c;也有可能另一個線程也要用...數據是被所有人共享的&#xff0c;所以就注定了 MySQL 這樣的服務在一個時…

uniapp:h5鏈接拉起支付寶支付

場景&#xff1a;APP內點擊支付寶支付&#xff0c;后臺返回類似鏈接https://qr.alipay.com/bax***********c3050 通常做法是&#xff0c;使用plus.runtime.openURL(deeplink);先打開瀏覽器&#xff0c;瀏覽器會提示打開支付寶&#xff0c;之后是支付流程。現在可以省略跳轉h5的…

吳恩達 Machine Learning(Class 3)

Week 11.1 K-means Cluster centroidK-means 是無監督學習中聚類算法的一種&#xff0c;核心在于更新聚類質心&#xff1b;首先將每個點分配給幾個聚類質心&#xff0c;取決于那些點離哪個質心更近&#xff1b;然后將幾個聚類質心移動到分配給他的所有點的平均值&#xff0c;不…

MyBatis 動態查詢語句詳解:讓 SQL 更靈活可控

MyBatis 動態查詢語句詳解&#xff1a;讓 SQL 更靈活可控 在日常的數據庫操作中&#xff0c;我們經常會遇到需要根據不同條件拼接 SQL 語句的場景。比如查詢用戶時&#xff0c;可能需要根據姓名、年齡、性別等多個條件進行篩選&#xff0c;而這些條件往往是動態變化的 —— 有時…

Java基礎語法three

一、一維數組一維數組初始化數據類型[] 數組名new 數據類型[數組長度]//動態初始化數據類型[] 數組名new 數據類型[]{值}//靜態初始化數據類型[] 數組名{值}數組長度一旦確定&#xff0c;就不可更改。數組是序排序&#xff1b;數組屬于引用數據類型的變量&#xff0c;數組的元素…

【數據結構】排序算法全解析:概念與接口

1.排序的概念及其運用 1.1 排序的概念 排序&#xff1a;所謂排序&#xff0c;就是使一串記錄&#xff0c;按照其中的某個或某些關鍵字的大小&#xff0c;遞增或遞減的排列起來的操作。 穩定性&#xff1a;假定在待排序的記錄序列中&#xff0c;存在多個具有相同的關鍵字的…