2

我們有兩個表,CustomerCustomerEvent都包含幾百萬行。在SQL Server 2000上,我們部署了一個名爲fn_CustomerEvent的UDF,該UDF基於兩個參數CustomerIDEventCode(例如,)來返回TRUEFALSESQL Server 2000和2005中用戶定義函數的性能

SELECT dbo.fn_CustomerEvent(1345678, 'Music') 

的UDF代碼:

CREATE FUNCTION [dbo].[fn_CustomerEvent](@CustomerID INT, @EviCode NVARCHAR(10)) 
RETURNS NVARCHAR(10) 
AS 
BEGIN 
    DECLARE @List NVARCHAR(10) 

    SELECT @List = CASE 
        WHEN COUNT(*) > 0 THEN 'TRUE' 
        ELSE 'FALSE' 
        END 
    FROM CustomerEvent 
    WHERE 
     CustomerID = @CustomerID 
     AND EviCode = @EviCode 

    RETURN @List 
END 

SQL Server 2000上的表現是偉大的。在3秒內返回TOP 5000行。例如,

SELECT TOP 5000 
    CustomerID, dbo.fn_CustomerEvent(1345678, 'Music') 
FROM [Table1] 

但是現在,我們正在向SQL Server 2005中相同的代碼,同一UDF,但性能從3秒大幅下降到1分20秒。

任何人都可以指出一個正確的方向,我應該從哪裏開始優化性能?

回答

1

UDF存在一個大問題:它們不適用於索引。如果你想獲得代碼重用和維護性能,我通常會建立一個計算列(可以被索引)或一個視圖。

+1

不確定你的意思是「它們不適用於索引」,你能詳細說明嗎? UDF的執行計劃可以使用索引。 – 2012-03-19 16:28:58

3

對每一行(即5000次)評估標量UDF。你既可以調用它一次,並將結果存儲在變量

DECLARE @Result nvarchar(10) 
SELECT @Result = dbo.fn_CustomerEvent(1345678, 'Music') 

SELECT TOP 5000 
    CustomerID, @Result 
FROM [Table1] 

,或者您可以使用內聯TVF(我也將使用的COUNTEXISTS代替)

CREATE FUNCTION CustomerEvent (@CustomerID INT, 
           @EviCode NVARCHAR(10)) 
RETURNS TABLE 
AS 
    RETURN 
    (SELECT CASE 
       WHEN EXISTS(SELECT * 
          FROM CustomerEvent 
          WHERE CustomerID = @CustomerID 
           AND EviCode = @EviCode) THEN 'TRUE' 
       ELSE 'FALSE' 
      END) 

Scalar functions, inlining, and performance: An entertaining title for a boring post更多有關這種技術。

0
CREATE FUNCTION CustomerEvent (@CustomerID INT, 
           @EviCode NVARCHAR(10)) 
RETURNS TABLE 
AS 
    RETURN 
    (SELECT COALESCE((SELECT 'TRUE' FROM CustomerEvent 
        WHERE 
         CustomerID = @CustomerID 
         AND EviCode = @EviCode) 
       , 'FALSE')) 

檢查索引,重建它們並更新您的統計信息。

+0

如果多於一行匹配「WHERE」,則會引發錯誤 – 2012-03-19 17:52:55

相關問題