同事編寫查詢:從 Base_Staff (人員) 關聯 Rpt_RegistForm (報備單) 統計約定書與報告數量。原查詢執行 ~10 秒,且重複掃描相同關聯結果集兩次 (一次統計約定書、一次統計報告)。
SELECT S.Name, S.AccountantCode,
(SELECT COUNT(*) FROM (
SELECT DISTINCT BusinessBackupId
FROM Biz_BusinessBackupCustomer
WHERE Id IN (
SELECT BusinessBackupCustomerId
FROM Rpt_RegistForm
WHERE (SignatureCPA1Id=S.Id OR SignatureCPA2Id=S.Id) AND DocStatus=30
)
) T) AS BNum,
CASE WHEN R.Id IS NULL THEN 0 ELSE 1 END AS Num,
R.ReportBackupDate
FROM Base_Staff S
LEFT JOIN Rpt_RegistForm R
ON (R.SignatureCPA1Id=S.Id OR R.SignatureCPA2Id=S.Id) AND R.DocStatus=30
WHERE S.UserType=3;
WITH StaffRegist AS (
SELECT
S.Name, S.AccountantCode, S.Id AS StaffId,
R.BusinessBackupCustomerId, R.Id AS RegistId,
R.SignatureCPA1Id, R.SignatureCPA2Id
FROM Base_Staff S
LEFT JOIN Rpt_RegistForm R
ON (R.SignatureCPA1Id = S.Id OR R.SignatureCPA2Id = S.Id)
AND R.DocStatus = 30
WHERE S.UserType = 3
)
SELECT
T0.Name, T0.AccountantCode,
(SELECT COUNT(*) FROM (
SELECT DISTINCT BusinessBackupId
FROM Biz_BusinessBackupCustomer B
JOIN StaffRegist C ON B.Id = C.BusinessBackupCustomerId
WHERE T0.AccountantCode = C.AccountantCode
) T1) AS 約定書數,
T0.報告數
FROM (
SELECT Name, AccountantCode, COUNT(BusinessBackupCustomerId) AS 報告數
FROM StaffRegist
GROUP BY Name, AccountantCode
) T0;
| 指標 | 原查詢 | CTE 重構 |
|---|---|---|
| 執行時間 | ~10 秒 | ~5 秒 |
| Rpt_RegistForm 掃描次數 | 2 次 (子查詢 + LEFT JOIN) | 1 次 (CTE 內) |
| Base_Staff 掃描次數 | 2 次 | 1 次 |
| 計畫複雜度 | 巢狀子查詢、重複運算子 | 線性流程、單一聚合 |
COUNT(BusinessBackupCustomerId) 自動略過 NULL 列,符合「無報備單則計 0」業務邏輯,無需 CASE。CTE 亦支援遞歸 (參見 CTE 遞歸指南),適用於組織架構、BOM、分類樹等層次結構查詢。
NEWID(), RAND()) 導致多次評估結果不一致。CTE 不僅提升可讀性,更能協助優化器識別共用子運算,消除重複掃描。本案例從 10 秒降至 5 秒,證明「邏輯去重」帶來的「物理去重」效果。開發複雜報表查詢時,養成「先定義 CTE 提取核心資料集,再疊加業務聚合」的分層思維。