在 T-SQL 開發中,純量函數 常被誤解為效能殺手。但若善用其「封裝邏輯、支援內嵌於查詢」的特性,能優雅解決兩類棘手問題:UPDATE 中需引用複雜計算邏輯,以及 彙總查詢中需逐列計算後再加總。本文透過兩個實戰案例深度解析。
需根據 TABLETASKPHASE 的工作進度百分比,計算 TABLEFMECA 中的關鍵度數值 Cvalue_M,並彙總更新至 TABLERELATION.CRITICALITY。因 UPDATE 不支援直接呼叫預存程序,傳統做法使用游標,效能差且程式碼冗長。
CREATE FUNCTION [dbo].[FUN_GETTIME] (@TASKPHASEID INT)
RETURNS FLOAT
AS
BEGIN
DECLARE @TASKID INT, @HOUR FLOAT, @PERCENT FLOAT, @RETURN FLOAT;
IF @TASKPHASEID IS NULL RETURN 0.0;
SELECT @TASKID = TASKID, @PERCENT = ISNULL(WORKPERCENT, 0) / 100.0
FROM TABLETASKPHASE WHERE ID = @TASKPHASEID;
SELECT @HOUR = ISNULL(TASKTIME, 0) FROM TABLETASK WHERE ID = @TASKID;
SET @RETURN = @HOUR * @PERCENT;
RETURN @RETURN;
END
CREATE PROCEDURE [dbo].[PROC_CALCCA] @ROID INT
AS
BEGIN
DECLARE @CA FLOAT;
UPDATE TABLEFMECA
SET Cvalue_M = ISNULL(MODERATE, 0) * ISNULL(FMERATE, 0)
* ISNULL(B.BASFAILURERATE, 0) * [dbo].[FUN_GETTIME](C.ID)
FROM TABLEFMECA
JOIN TABLERELATION B ON B.ID = @ROID
JOIN TABLETASKPHASE C ON C.ID = TABLEFMECA.TASKPHASEID
WHERE TABLEFMECA.ROID = @ROID;
SELECT @CA = SUM(ISNULL(Cvalue_M, 0)) FROM TABLEFMECA WHERE ROID = @ROID;
UPDATE TABLERELATION SET CRITICALITY = @CA WHERE ID = @ROID;
END
需根據零件、環境、資料來源、品質等級、數量等多維參數查詢失效率,再乘以工作百分比加總。傳統做法需游標逐列計算並累加中間值,但 SQL Server 2000+ 支援 SUM(函數運算式) 語法,可直接在彙總中完成。
SUM ( [ ALL | DISTINCT ] expression )
-- expression 可為:常數、欄位、函數、或算術/位元/字串運算式的任意組合
CREATE FUNCTION [dbo].[FUN_RATE] (
@PARTID INT, @ENID INT, @SOURCEID INT, @QUALITYID INT, @COUNT INT
)
RETURNS FLOAT
AS
BEGIN
DECLARE @QXS FLOAT, @G FLOAT, @RATE FLOAT;
IF @ENID IS NULL OR @PARTID IS NULL OR @SOURCEID IS NULL OR @QUALITYID IS NULL
RETURN 0.0;
SELECT @QXS = ISNULL(XS, 0) FROM TABLEQUALITY WHERE ID = @QUALITYID;
SELECT @G = ISNULL(FRATE_G, 0)
FROM TABLEFAILURERATE
WHERE SUBKINDID = @PARTID
AND ENID = @ENID
AND DATASOURCEID = @SOURCEID
AND ( (ISNULL(MINCOUNT, 0) <= ISNULL(@COUNT, 0) AND ISNULL(MAXCOUNT, 0) >= ISNULL(@COUNT, 0))
OR (ISNULL(@COUNT, 0) > ISNULL(MAXCOUNT, 0)) );
SET @RATE = ISNULL(@QXS * @G, 0);
RETURN @RATE;
END
CREATE PROC PROC_FAULTRATE
@PARTID INTEGER, @QUALITYID INTEGER, @SOURCEID INTEGER,
@COUNT INTEGER, @ROID INT, @GRADE INT, @RATE FLOAT = 0 OUTPUT
AS
BEGIN
DECLARE @TASKID INT;
SET @RATE = 0.0;
SELECT @TASKID = ISNULL(TASKPROID, -1)
FROM TABLERELATION
WHERE ID = (SELECT PID FROM TABLERELATION WHERE ID = @ROID);
IF @TASKID = -1 OR @GRADE = 1 BEGIN
SET @RATE = 0; RETURN;
END
SELECT @RATE = SUM( [dbo].[FUN_RATE](@PARTID, ENID, @SOURCEID, @QUALITYID, @COUNT)
* ISNULL(WORKPERCENT, 0) / 100.0 )
FROM TABLETASKPHASE
WHERE TASKID = @TASKID;
END
SUM() 完成「逐列呼叫函數 → 乘權重 → 加總」全流程RETURN 的純量函數,較易被優化器內嵌;多語句表值函數或複雜純量函數可能導致逐列執行(RBAR)CROSS APPLY 配合內嵌表值函數 (iTVF) 通常效能更優WITH SCHEMABINDING 可提升優化器決策品質Compute Scalar 操作符成本,必要時改寫為內聯運算式純量函數在 UPDATE 內嵌計算 與 彙總運算式重構 兩大場景中,能將原本需要游標或中間表的程序式邏輯,轉化為宣告式、集合導向的 SQL 陳述式。關鍵在於:函數邏輯單一、確定性、無副作用,並搭配適當的索引與統計資料,讓優化器發揮最大效能。