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

相关问题