加快查询速度

时间:2017-04-26 08:05:23

标签: sql-server function

我有这个功能,可以将工作日添加到特定日期并返回日期:

ALTER FUNCTION [dbo].[CalcWorkDaysAddDays]
    (@StartDate AS DATETIME, @Days AS INT) 
RETURNS DATE 
AS 
BEGIN 
    DECLARE @Count INT = 0 
    DECLARE @WorkDay INT = 0 

    DECLARE @Date DATE = @StartDate 

    WHILE @WorkDay < @Days 
    BEGIN 
        SET @Count = @Count + 1 

        SET @Date = DATEADD(DAY, @Count, @StartDate) 

        IF NOT (DATEPART(WEEKDAY, @Date) IN (1, 7) 
                OR EXISTS (SELECT * 
                           FROM Holidays_Weeknds 
                           WHERE Date = @Date)) 
        BEGIN 
            SET @WorkDay = @WorkDay + 1 
        END 
    END 

    RETURN @Date 
END 

此功能在小型数据集中完美运行。但是我的表中有近70k的记录,我需要在我的表中使用此函数超过10列。问题是当我使用这个功能时,运行时间太长。有什么办法可以加快速度,或者修改更新表格中列的UPDATE语句吗?我的更新语句如下所示:

UPDATE pt
SET [Predicted_Eng_Comp_date] = [dbo].[CalcWorkDaysAddDays](pt.Actual_Eng_Start_date, 20)
FROM [cntrra20-devbrs].PST.[dbo].[tbl_Project_tracker1] pt

2 个答案:

答案 0 :(得分:2)

一些一般性提示:

  • 标量函数表现不佳
  • WHILE循环(实际上是任何循环)都是糟糕的表现者
  • 程序性思维是错误的方法

如果你需要一个函数,最好是一个内联表值函数,即使它只返回一个标量值。

您的问题

对于一个持久的约会表来说,这是一个完美的情况。

您找到一个示例here
Aaron Bertrand提供了一个很好的方法here 使用您的假期表向表中添加IsHoliday - 标志。

这是一个很小的模拟来显示原则

DECLARE @mockup TABLE(TheDate DATE, DaysName VARCHAR(100),IsWeekday BIT, IsHoliday BIT)
INSERT INTO @mockup VALUES
 ({d'2016-12-19'},'Mo',1,0)
,({d'2016-12-20'},'Tu',1,0)
,({d'2016-12-21'},'We',1,0)
,({d'2016-12-22'},'Th',1,0)
,({d'2016-12-23'},'Fr',1,0)
,({d'2016-12-24'},'Sa',0,0)
,({d'2016-12-25'},'Su',0,1)
,({d'2016-12-26'},'Mo',1,1)
,({d'2016-12-27'},'Tu',1,0)
,({d'2016-12-28'},'We',1,0)
,({d'2016-12-29'},'Th',1,0)
,({d'2016-12-30'},'Fr',1,0)
,({d'2016-12-31'},'Sa',0,0)
,({d'2017-01-01'},'Su',0,1)
,({d'2017-01-02'},'Mo',1,0)
,({d'2017-01-03'},'Tu',1,0)
,({d'2017-01-04'},'We',1,0);

- 您的变量

DECLARE @d DATE={d'2016-12-20'};
DECLARE @WorkdaysToAdd INT=5;

- 查询选择TOP X排序ASC,然后选择TOP 1排序DESC

SELECT TOP 1 TheDate
FROM
(
    SELECT TOP (@WorkdaysToAdd) TheDate 
    FROM @mockup 
    WHERE TheDate>@d
      AND IsWeekday=1
      AND IsHoliday=0 
    ORDER BY TheDate ASC
) AS t
ORDER BY t.TheDate DESC

更新

你可以从中创建一个函数,或者将它括义直接包含在你的UPDATE查询中(而不是你的函数)。

答案 1 :(得分:0)

具有功能的列非常慢。尽量避免:

   declare @MinStartDate as date = '1/1/2010'
   declare @MaxEndDate as date = '1/1/2020'
   declare @numberofdays int = 20

   ;WITH res(val)
    AS
    ( 
    select val from (select @MinStartDate as val) as resy
    union all
    select dateadd(d,1, res.val) from res where res.val < @MaxEndDate
    )
    UPDATE pt
    set [Predicted_Eng_Comp_date]= a.NUMDAYS
    from [cntrra20-devbrs].PST.[dbo].[tbl_Project_tracker1] pt
        inner join (
            SELECT  r.val, count(*) as NUMDAYS
            FROM [cntrra20-devbrs].PST.[dbo].[tbl_Project_tracker1] pt
                inner join res r on pt.Actual_Eng_Start_date = r.val
                left join Holidays_Weeknds h on r.val = h.[Date]
            where DATEPART(WEEKDAY, r.val) NOT IN (1,7) and h.[Date] is null 
                 and val>=pt.Actual_Eng_Start_date and val<=dateadd(d,@numberofdays, pt.Actual_Eng_Start_date)
             group by r.val) a on pt.Actual_Eng_Start_date = a.val
    option (MAXRECURSION 32767)

根据计算,您可能希望更改&#39; val&lt; = dateadd&#39; val小于。