從全量客戶表中,按機構、公司、地區、渠道四維分組,針對特定渠道(1027、1028)各自取銷量前 10% 客戶進行電話調查。
SELECT DISTINCT
b.OrgID, b.CompanyID, b.AreaID, b.CustChannelID, b.CustID, b.SaleTotalQty,
GETDATE() AS ProcessTime
FROM KDS400TelSurveyCustAll_Temp tmp1
CROSS APPLY (
SELECT TOP 10 PERCENT *
FROM KDS400TelSurveyCustAll_Temp tmp2
WHERE tmp1.OrgID = tmp2.OrgID
AND tmp1.CompanyID = tmp2.CompanyID
AND tmp1.AreaID = tmp2.AreaID
AND tmp1.CustChannelID = tmp2.CustChannelID
AND tmp2.CustChannelID IN (1027, 1028)
ORDER BY tmp2.OrgID, tmp2.CompanyID, tmp2.AreaID, tmp2.AreaType, tmp2.CustChannelID
) b;
| 特性 | CROSS APPLY | INNER JOIN |
|---|---|---|
| 右表參考左表列 | ✅ 支援 | ❌ 不支援 |
| 每行獨立計算 | ✅ 是 | ❌ 集合運算 |
| TOP N 按組計算 | ✅ 原生支援 | 需窗口函數 |
| 執行計畫 | Nested Loops | Hash/Merge Join |
外層 tmp1 掃描每一行
│
▼
內層 tmp2 依外層鍵值過濾
│
▼
按銷量降序排序
│
▼
取前 10% 記錄返回
│
▼
外層 SELECT DISTINCT 去重
CREATE INDEX IX_Survey_Grouping
ON KDS400TelSurveyCustAll_Temp (OrgID, CompanyID, AreaID, CustChannelID, SaleTotalQty DESC)
INCLUDE (CustID, AreaType);
UPDATE STATISTICS ... WITH FULLSCAN。WITH Ranked AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY OrgID, CompanyID, AreaID, CustChannelID
ORDER BY SaleTotalQty DESC
) AS rn,
COUNT(*) OVER (
PARTITION BY OrgID, CompanyID, AreaID, CustChannelID
) AS cnt
FROM KDS400TelSurveyCustAll_Temp
WHERE CustChannelID IN (1027, 1028)
)
SELECT OrgID, CompanyID, AreaID, CustChannelID, CustID, SaleTotalQty, GETDATE()
FROM Ranked
WHERE rn <= CEILING(cnt * 0.1);
優點:單次掃描、並行度高。
缺點:記憶體壓力大、需計算精確行數。
SELECT DISTINCT
b.*
FROM KDS400TelSurveyCustAll_Temp tmp1
CROSS APPLY (
SELECT *
FROM KDS400TelSurveyCustAll_Temp tmp2
WHERE tmp1.OrgID = tmp2.OrgID
AND tmp1.CompanyID = tmp2.CompanyID
AND tmp1.AreaID = tmp2.AreaID
AND tmp1.CustChannelID = tmp2.CustChannelID
AND tmp2.CustChannelID IN (1027, 1028)
AND tmp2.SaleTotalQty >= (
SELECT APPROX_PERCENTILE(0.9) WITHIN GROUP (ORDER BY SaleTotalQty)
FROM KDS400TelSurveyCustAll_Temp
WHERE OrgID = tmp1.OrgID
AND CompanyID = tmp1.CompanyID
AND AreaID = tmp1.AreaID
AND CustChannelID = tmp1.CustChannelID
)
) b;
適用:超大數據集近似計算,效能極佳但有誤差。
CROSS APPLY + TOP PERCENT 可讀性最佳。ROW_NUMBER() 配合並行查詢(MAXDOP)。Actual Rows vs Estimated Rows 偏差。