在 SQL 查詢中,查詢的執(zhí)行順序并不是按照語句中編寫的順序執(zhí)行的,實際上,SQL 的執(zhí)行順序是由數(shù)據(jù)庫查詢優(yōu)化器決定的。理解 SQL 查詢的執(zhí)行順序?qū)φ{(diào)優(yōu)查詢性能非常重要,特別是在涉及復雜查詢時。
1. SQL 查詢執(zhí)行的順序
雖然 SQL 查詢語句看起來是從上到下逐步執(zhí)行的,但數(shù)據(jù)庫會根據(jù)內(nèi)部的執(zhí)行計劃重新安排各個部分的執(zhí)行順序。標準的 SQL 執(zhí)行順序如下:
FROM: 從數(shù)據(jù)源(表、視圖或連接)中檢索數(shù)據(jù)。
ON: 對連接條件進行過濾(如果使用了連接操作,如 JOIN
)。
JOIN: 執(zhí)行連接操作,合并不同的數(shù)據(jù)集。
WHERE: 對數(shù)據(jù)應(yīng)用過濾條件,排除不符合條件的行。
GROUP BY: 對數(shù)據(jù)進行分組。
HAVING: 對分組后的數(shù)據(jù)應(yīng)用過濾條件。
SELECT: 選擇并返回列,確定需要查詢的字段。
DISTINCT: 去除重復的行。
ORDER BY: 對結(jié)果進行排序。
LIMIT / OFFSET: 限制返回的結(jié)果集大小或偏移量。
注意:SELECT
語句是在查詢的最后階段執(zhí)行的,它是結(jié)果集返回給用戶的那一部分。但數(shù)據(jù)庫通常會先執(zhí)行數(shù)據(jù)檢索、過濾、分組等操作,再進行選擇列和去重的操作。
2. 執(zhí)行順序分析
讓我們通過一個具體的例子來詳細分析 SQL 查詢的執(zhí)行順序。
假設(shè)我們有以下 SQL 查詢:
SELECT customer_id, COUNT(order_id)
FROM orders
JOIN customers ON orders.customer_id = customers.customer_id
WHERE order_date > '2024-01-01'
GROUP BY customer_id
HAVING COUNT(order_id) > 5
ORDER BY COUNT(order_id) DESC
LIMIT 10;
執(zhí)行步驟:
FROM:
JOIN:
ON:
WHERE:
GROUP BY:
HAVING:
SELECT:
DISTINCT (如果存在):
ORDER BY:
LIMIT / OFFSET:
3. 為什么 SELECT 是最后執(zhí)行的?
理解 SELECT
作為最后執(zhí)行的操作,需要從 SQL 查詢的優(yōu)化角度考慮。SQL 查詢的設(shè)計本意是讓數(shù)據(jù)庫引擎從底層開始處理數(shù)據(jù)(即從數(shù)據(jù)源提取數(shù)據(jù)、連接、過濾),直到用戶需要的最終結(jié)果,這時才是數(shù)據(jù)選擇的階段。
以下是具體的原因:
數(shù)據(jù)檢索與過濾優(yōu)先:執(zhí)行計劃從底層表中檢索數(shù)據(jù),并根據(jù)查詢條件(WHERE
)和連接條件(JOIN
)過濾數(shù)據(jù)。如果在這時就進行 SELECT
,將會浪費資源提取不必要的字段。
聚合與分組優(yōu)先:在執(zhí)行 SELECT
之前,數(shù)據(jù)庫需要先進行數(shù)據(jù)的分組(GROUP BY
),然后根據(jù)分組的結(jié)果應(yīng)用聚合函數(shù)(如 COUNT()
、SUM()
、AVG()
等)。只有在分組和聚合之后,才能知道哪些列需要被選取,并根據(jù)這些結(jié)果生成最終的輸出。
排序與限制:數(shù)據(jù)庫通常會在生成了滿足查詢條件的完整結(jié)果集后,才進行排序(ORDER BY
)和限制(LIMIT
)操作。如果早早執(zhí)行 SELECT
,排序和去重可能會浪費資源。
4. 執(zhí)行順序的示例:
假設(shè)你有以下查詢:
SELECT product_id, COUNT(order_id)
FROM orders
JOIN products ON orders.product_id = products.product_id
WHERE order_date > '2023-01-01'
GROUP BY product_id
HAVING COUNT(order_id) > 10
ORDER BY COUNT(order_id) DESC;
執(zhí)行步驟(按順序):
FROM: 從 orders
和 products
表中獲取數(shù)據(jù)。
JOIN: 將 orders
表和 products
表連接起來,條件是 orders.product_id = products.product_id
。
WHERE: 過濾出 order_date > '2023-01-01'
的記錄。
GROUP BY: 按 product_id
對結(jié)果進行分組。
HAVING: 保留那些 COUNT(order_id) > 10
的產(chǎn)品。
SELECT: 返回 product_id
和計算的 COUNT(order_id)
。
ORDER BY: 按照訂單數(shù)降序排列結(jié)果。
LIMIT (如果有的話): 限制返回的行數(shù)。
5. 總結(jié)
SQL 查詢的執(zhí)行順序從邏輯上與我們編寫查詢時的順序不同,SQL 引擎會根據(jù)執(zhí)行計劃優(yōu)化查詢。
SELECT
是在查詢的最后執(zhí)行的,原因是查詢執(zhí)行計劃需要先完成數(shù)據(jù)檢索、連接、過濾、分組等操作,然后再根據(jù)需要選擇和輸出列。
SELECT
作為最后步驟是為了確保只有在完成所有計算和過濾后,數(shù)據(jù)庫才會提取最終所需的列,從而避免無謂的計算和資源浪費。
理解 SQL 查詢的執(zhí)行順序是優(yōu)化 SQL 查詢性能和調(diào)試復雜查詢的重要基礎(chǔ)。
閱讀原文:原文鏈接
該文章在 2025/2/5 17:21:48 編輯過