SQL Server(T-SQL):多次避免调用标量函数

时间:2017-06-07 12:38:44

标签: sql-server-2008 tsql user-defined-functions

我有一个存储过程,它会执行SELECT以返回一些行。在SELECT中,我需要检查一个条件,以便为某些列返回正确的值。这个条件包括标量函数。所有时间都会使用与正在处理的行相同的参数调用标量函数,请参见下文:

SELECT
    Id,
    Name,
    Surname,
    CASE WHEN (dbo.GetNumTravels(Id) >= 50)
        THEN 10
        ELSE 99
    END as Factor1,
    CASE WHEN (dbo.GetNumTravels(Id) >= 50)
        THEN 15
        ELSE -1
    END as Factor2,
    CASE WHEN (dbo.GetNumTravels(Id) >= 50)
        THEN 30
        ELSE 70
    END as Factor3
FROM 
    Employees
WHERE 
    DepartmentId = 100

我担心性能,我的意思是,我不喜欢称标量函数dbo.GetNumTravels倍数,所以如何避免这种情况,只调用一次,然后一直使用它我需要它? / p>

3 个答案:

答案 0 :(得分:2)

标量用户定义的函数因性能不佳而臭名昭着。如果您可以将其转换为内联表值函数,您可以期望看到性能提升。

如果将标量函数转换为内联表值函数,则可以使用cross apply()为每行调用一次,如下所示:

select
     Id,
     Name,
     Surname,
     case when x.NumTravels >= 50
        then 10
        else 99
     end as Factor1,
     case when x.NumTravels >= 50)
        then 15
        else -1
     end as Factor2,
     case when x.NumTravels >= 50
        then 30
        else 70
     end as Factor3
from Employees
  cross apply dbo.GetNumTravels_itvf(e.Id) x
where DepartmentId = 100

参考:

答案 1 :(得分:1)

你可以通过使用派生表概念实现这一点,在派生表中我们曾经只调用一次函数dbo.GetNumTravels(Id)并在外部查询中使用它的输出,这可能有助于通过避免多次调用来获得某种程度的性能功能相同。

SELECT 
       Id,
       Name,
       Surname,
       CASE WHEN (NumTravelsID >= 50)  THEN 10  ELSE 99 END as Factor1,
       CASE WHEN (NumTravelsID >= 50)  THEN 15  ELSE -1 END as Factor2,
       CASE WHEN (NumTravelsID >= 50)  THEN 30  ELSE 70 END as Factor3
FROM (
         SELECT
            Id,
            Name,
            Surname,
            dbo.GetNumTravels(Id) as NumTravelsID
         FROM Employees
         WHERE DepartmentId = 100  
 )M

答案 2 :(得分:0)

我不确定表演(无论如何,考虑其他答案你的考试也是如此),但我想测试一下。我试图减少功能的使用和CASE的使用。请告诉我

SELECT A.*
    , 10*F0+99*~F0 AS FACTOR1
    , 15*F0-1*~F0 AS FACTOR2
    , 30*F0+70*~F0 AS FACTOR3
FROM (
    SELECT
     Id,
     Name,
     Surname,
    CAST(CASE WHEN (dbo.GetNumTravels(Id) >= 50) THEN  1  ELSE 0 END AS BIT) AS F0     
    FROM Employees
    WHERE DepartmentId = 100
     ) A