SELECT * FROM (
SELECT subject, COUNT(Subject) AS cout
FROM Questions
WHERE UserID = 'banianji' AND AskDate > '2011-01-01' AND AskDate < '2014-01-01'
GROUP BY Subject
) AS a
WHERE a.cout = (
SELECT MAX(cout) FROM (
SELECT subject, COUNT(Subject) AS cout
FROM Questions
WHERE UserID = 'banianji' AND AskDate > '2011-01-01' AND AskDate < '2014-01-01'
GROUP BY Subject
) AS b
);
核心缺陷:相同的聚合子查詢執行了兩次,資料量大時效能嚴重下降,且維護困難(修改條件需改兩處)。
WITH cte AS (
SELECT subject, COUNT(Subject) AS cout
FROM Questions
WHERE UserID = 'banianji'
AND AskDate > '2011-01-01'
AND AskDate < '2014-01-01'
GROUP BY Subject
)
SELECT * FROM cte AS a
WHERE a.cout = (SELECT MAX(cout) FROM cte AS b);
| 維度 | 原始巢狀查詢 | CTE 寫法 |
|---|---|---|
| 重複計算 | 聚合查詢執行兩次 | 只執行一次,結果暫存 |
| 可讀性 | 層層巢狀,難以閱讀 | 邏輯線性,自上而下 |
| 維護性 | 修改 WHERE 條件需改兩處 | 單一來源,修改一處 |
| 除錯 | 難以單獨測試子查詢 | 可獨立執行 CTE 部分驗證 |
| 遞迴支援 | 不支援 | 支援遞迴 CTE(組織架構、BOM) |
CTE 結果可能被暫存為臨時表,適合重複引用場景。但若 CTE 只被引用一次,優化器可能選擇內聯展開而非物化。
WITH cte AS (SELECT ... ) SELECT * FROM cte JOIN cte ... 或建立臨時表。-- 臨時表(Session 級,自動清理)
CREATE TEMPORARY TABLE tmp_subject_stats AS
SELECT subject, COUNT(*) AS cnt
FROM Questions
WHERE UserID = 'banianji' AND AskDate BETWEEN '2011-01-01' AND '2014-01-01'
GROUP BY subject;
SELECT * FROM tmp_subject_stats
WHERE cnt = (SELECT MAX(cnt) FROM tmp_subject_stats);
-- 索引加速
CREATE INDEX idx_cnt ON tmp_subject_stats(cnt);
(UserID, AskDate, Subject) 複合索引可支援此查詢的過濾與分組。UPDATE STATISTICS / ANALYZE TABLE 確保優化器有準確基數估計。EXPLAIN / SET STATISTICS IO ON 觀察實際掃描行數、索引使用。WITH ranked AS (
SELECT subject, COUNT(*) AS cnt,
RANK() OVER (ORDER BY COUNT(*) DESC) AS rk
FROM Questions
WHERE UserID = 'banianji' AND AskDate BETWEEN '2011-01-01' AND '2014-01-01'
GROUP BY subject
)
SELECT subject, cnt FROM ranked WHERE rk = 1;
優點:單次掃描、無需自我連接、語意清晰。
SELECT subject, COUNT(*) AS cnt
FROM Questions q1
WHERE UserID = 'banianji' AND AskDate BETWEEN '2011-01-01' AND '2014-01-01'
GROUP BY subject
HAVING COUNT(*) = (
SELECT MAX(cnt) FROM (
SELECT COUNT(*) AS cnt
FROM Questions q2
WHERE UserID = 'banianji' AND AskDate BETWEEN '2011-01-01' AND '2014-01-01'
GROUP BY subject
) t
);
將重複的巢狀子查詢重構為 CTE 是提升可讀性、維護性與效能的首選手段。現代資料庫(PG, Oracle, SQL Server, MySQL 8.0+)均完整支援 CTE 與窗口函數,建議優先採用 WITH ... RANK() OVER ... 模式解決「取得極值對應所有列」問題。配合適當索引、統計資訊維護與執行計畫驗證,可獲得穩定高效的查詢效能。