用户定义的函数SQL Server

时间:2018-01-22 03:39:37

标签: sql sql-server performance user-defined-functions

性能调优很差在SQL Server中继承UDF。

最近我获得了一个新的SQL Server环境。我已经能够更快地制作不同的部分,因为我遇到了一个调用两个标量值函数的表值函数。问题是性能调优UDF是我非常陌生的东西之一,我想帮助我如何更快地实现这一点。

我理解标量值函数用于逐行处理。所以我正在寻找一种方法来加快速度。有人可以请帮助。以下是功能。

标量值函数1.添加它只是为了显示最新情况。

ALTER FUNCTION [dbo].[AgingFactorOverride]
    (@Aging_Factor FLOAT, 
     @Company_ID INT, 
     @Survey_ID INT, 
     @Country_Code VARCHAR(50), 
     @Effective_Date DATETIME)
RETURNS FLOAT
WITH EXEC AS CALLER
AS
BEGIN
    DECLARE @RetVal FLOAT

    BEGIN
        SELECT @RetVal = MAX(Aging_Factor) 
        FROM companysurveycountryaging csca 
        WHERE csca.company_id = @Company_ID 
          AND csca.Country_Code = @Country_Code 
          AND ISNULL(csca.survey_id, '') = CASE WHEN csca.survey_id IS NOT NULL
                                                   THEN @Survey_ID 
                                                   ELSE '' 
                                           END
          AND csca.effective_date = (SELECT MAX(cscaa.effective_date) 
                                     FROM companysurveycountryaging cscaa 
                                     WHERE cscaa.company_id = @Company_ID 
                                       AND cscaa.Country_Code = @Country_Code    
                                       AND ISNULL(cscaa.survey_id, '') = CASE WHEN cscaa.survey_id IS NOT NULL THEN @Survey_ID ELSE '' END 
                                       AND cscaa.effective_date <= @Effective_Date)

        IF @RetVal IS NULL
        BEGIN
            SET @RetVal = @Aging_Factor
        END
    END

    RETURN @RetVal
END

标量值函数2.

ALTER FUNCTION [dbo].[AgeData]
(@ValToAge float, @StartDate datetime, @EndDate datetime, @AgingFactor float)
RETURNS float
WITH EXEC AS CALLER
AS
BEGIN
Declare @RetVal float,@NumMonths float

if @AgingFactor is not NULL
  Begin
    Set @NumMonths=DateDiff(month,@StartDate,@EndDate);
    Set @RetVal=@ValToAge*(1+(((@AgingFactor/12)*@NumMonths)/100));
  End
else
  set @RetVal=@ValToAge;
Return @RetVal
END

表值函数 - 以下是调用上述标量函数的查询示例。

Select
@Base25=ISNULL(dbo.AgeData(sd.base25,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@Base50=ISNULL(dbo.AgeData(sd.base50,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@Base75=ISNULL(dbo.AgeData(sd.base75,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@BaseAVG=ISNULL(dbo.AgeData(sd.baseAVG,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@TCC25=ISNULL(dbo.AgeData(sd.TCC25,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@TCC50=ISNULL(dbo.AgeData(sd.TCC50,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@TCC75=ISNULL(dbo.AgeData(sd.TCC75,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@TCCAVG=ISNULL(dbo.AgeData(sd.TCCAVG,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@Base10=ISNULL(dbo.AgeData(sd.Base10,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
@Base90=ISNULL(dbo.AgeData(sd.Base90,s.effective_Date,@Effective_Date,dbo.AgingFactorOverride(cs.aging_factor,@Company_ID,sd.Survey_ID,sd.Country_Code,@Effective_Date)),0),
from surveydata sd, surveys s,companysurveys cs
where cs.company_id=s.Company_ID and cs.survey_id=s.survey_id and s.survey_id=sd.survey_id

如果您还需要其他任何东西可以让这项工作更好,请告诉我。

1 个答案:

答案 0 :(得分:0)

将标量函数更改为内联表值函数

GO

ALTER FUNCTION [dbo].[Agingfactoroverride] (@Aging_Factor   FLOAT,
                                            @Company_ID     INT,
                                            @Survey_ID      INT,
                                            @Country_Code   VARCHAR(50),
                                            @Effective_Date DATETIME)
RETURNS TABLE
WITH EXEC AS CALLER
AS
    RETURN
      (SELECT Isnull((SELECT Max(Aging_Factor)
                      FROM   (SELECT Rnk = Dense_rank() OVER(ORDER BY effective_date DESC),
                                     Aging_Factor
                              FROM   companysurveycountryaging csca
                              WHERE  csca.company_id = @Company_ID
                                     AND csca.Country_Code = @Country_Code
                                     AND (csca.survey_id = @Survey_ID or csca.survey_id is null)
                                     AND csca.effective_date <= @Effective_Date) a
                      WHERE  Rnk = 1), @Aging_Factor))

GO

ALTER FUNCTION [dbo].[Agedata] (@ValToAge    FLOAT,
                                @StartDate   DATETIME,
                                @EndDate     DATETIME,
                                @AgingFactor FLOAT)
RETURNS TABLE
WITH EXEC AS CALLER
AS
    RETURN
      (SELECT CASE
                WHEN @AgingFactor IS NOT NULL THEN @ValToAge * ( 1 + ( ( ( @AgingFactor / 12 ) * Datediff(month, @StartDate, @EndDate) ) / 100 ) )
                ELSE @ValToAge
              END); 

使用outer apply调用函数

SELECT Base25,
       Base50,
       Base75,
       BaseAVG,
       TCC25,
       TCC50,
       TCC75,
       TCCAVG,
       Base10,
       Base90
FROM   surveydata sd
       INNER JOIN surveys s
               ON s.survey_id = sd.survey_id
       INNER JOIN companysurveys cs
               ON cs.company_id = s.Company_ID
                  AND cs.survey_id = s.survey_id
       OUTER apply (SELECT Base25 = Isnull(dbo.Agedata(sd.base25, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           Base50 = Isnull(dbo.Agedata(sd.base50, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           Base75 = Isnull(dbo.Agedata(sd.base75, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           BaseAVG = Isnull(dbo.Agedata(sd.baseAVG, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           TCC25 = Isnull(dbo.Agedata(sd.TCC25, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           TCC50 = Isnull(dbo.Agedata(sd.TCC50, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           TCC75 = Isnull(dbo.Agedata(sd.TCC75, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           TCCAVG = Isnull(dbo.Agedata(sd.TCCAVG, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           Base10 = Isnull(dbo.Agedata(sd.Base10, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0),
                           Base90 = Isnull(dbo.Agedata(sd.Base90, s.effective_Date, @Effective_Date, dbo.Agingfactoroverride(cs.aging_factor, @Company_ID, sd.Survey_ID, sd.Country_Code, @Effective_Date)), 0)) oa