查询需要一分钟以上的时间才能执行

时间:2019-03-07 10:34:24

标签: tsql

执行我当前的查询需要1:16分钟。那太久了。这是我的查询像atm的样子:

SELECT

    [plugin.tickets].[Ticket].Id,

    [plugin.tickets].[Ticket].Title,

    [plugin.tickets].[Ticket].Created,

    [plugin.tickets].[Ticket].StartProgress,

    [dbo].[worktime]([plugin.tickets].[Ticket].Created, GetDate()) AS OpenstaandeTijdInUren,

    [plugin.tickets].[Ticket].firstresponse,

    DATEDIFF(HOUR, [plugin.tickets].[Ticket].Created, [plugin.tickets].[Ticket].FirstResponse) AS ReactietijdInUren,

    [plugin.tickets].[Ticket].Status,

    [plugin.tickets].[Ticket].Priority,

         DATEDIFF (MINUTE, [plugin.tickets].[Ticket].Created, [plugin.tickets].[Ticket].EndProgress) as OplostijdTicketInUren



FROM

    [plugin.tickets].[Ticket]

WHERE

    [dbo].[worktime](

        [plugin.tickets].[Ticket].Created, GetDate()

    ) >= 1

    AND (

        [plugin.tickets].[Ticket].status <= 2

    )

ORDER BY

    [plugin.tickets].[Ticket].id

在查询中有一个我使用的函数。该函数计算两个日期之间的小时差。为了计算除假期之外的时间,我制作了一个表格,其中包含即将到来的10年的假期。这很可能就是执行查询需要这么长时间的原因,因为查询的每一行都包含与假日表相同的日期。但是我不确定该问题的解决方案是什么?

这是我的功能:

ALTER FUNCTION [dbo].[WorkTime]

(

    @StartDate DATETIME,

    @FinishDate DATETIME

)

RETURNS BIGINT

AS

BEGIN

    DECLARE @Temp BIGINT

    SET @Temp=0



       --DECLARE @hdays Table (values) date

       --insert into @hdays

       --select [Datum_Feestdag]  --= (Datum_feestdag)

       --from [dbo].[Feestdagen] 



    DECLARE @FirstDay DATE

    SET @FirstDay = CONVERT(DATE, @StartDate, 112)



    DECLARE @LastDay DATE

    SET @LastDay = CONVERT(DATE, @FinishDate, 112)



    DECLARE @StartTime TIME

    SET @StartTime = CONVERT(TIME, @StartDate)



    DECLARE @FinishTime TIME

    SET @FinishTime = CONVERT(TIME, @FinishDate)



    DECLARE @WorkStart TIME

    SET @WorkStart = '08:00'



    DECLARE @WorkFinish TIME

    SET @WorkFinish = '18:00'



    DECLARE @DailyWorkTime BIGINT

    SET @DailyWorkTime = DATEDIFF(HOUR, @WorkStart, @WorkFinish)



    IF (@StartTime<@WorkStart)

    BEGIN

        SET @StartTime = @WorkStart

    END

    IF (@FinishTime>@WorkFinish)

    BEGIN

        SET @FinishTime=@WorkFinish

    END

    IF (@FinishTime<@WorkStart)

    BEGIN

        SET @FinishTime=@WorkStart

    END

    IF (@StartTime>@WorkFinish)

    BEGIN

        SET @StartTime = @WorkFinish

    END

    DECLARE @CurrentDate DATE

    SET @CurrentDate = @FirstDay

    DECLARE @LastDate DATE

    SET @LastDate = @LastDay





    WHILE(@CurrentDate<=@LastDate)

    BEGIN     

        IF

             (DATEPART(dw, @CurrentDate)!=1 AND DATEPART(dw, @CurrentDate)!=7)

             and @CurrentDate not in (select Datum_feestdag from Feestdagen)

        --@CurrentDate not in (@hdays)

             BEGIN

            IF (@CurrentDate!=@FirstDay) AND (@CurrentDate!=@LastDay)

            BEGIN

                SET @Temp = @Temp + @DailyWorkTime

            END

            --IF it starts at startdate and it finishes not this date find diff between work finish and start as hours

            ELSE IF (@CurrentDate=@FirstDay) AND (@CurrentDate!=@LastDay)

            BEGIN

                SET @Temp = @Temp + DATEDIFF(HOUR, @StartTime, @WorkFinish)

            END



            ELSE IF (@CurrentDate!=@FirstDay) AND (@CurrentDate=@LastDay)

            BEGIN

                SET @Temp = @Temp + DATEDIFF(HOUR, @WorkStart, @FinishTime)

            END

            --IF it starts and finishes in the same date

            ELSE IF (@CurrentDate=@FirstDay) AND (@CurrentDate=@LastDay)

            BEGIN

                SET @Temp = DATEDIFF(HOUR, @StartTime, @FinishTime)

            END

        END

        SET @CurrentDate = DATEADD(day, 1, @CurrentDate)

    END



    -- Return the result of the function

    IF @Temp<0

    BEGIN

        SET @Temp=0

    END

    RETURN @Temp

END

1 个答案:

答案 0 :(得分:1)

您的查询花费的时间比最可能花费的时间长,因为您正在while循环中逐行计算值。从根本上说,这不是应该使用SQL数据库的方式。

尝试通过组合和比较数据集来解决问题,而不是遍历表中的每个值。您开发自己的解决方案的起点将是这样的:

declare @t table(id int,StartDate datetime, EndDate datetime);
insert into @t values
 (1,'2019/01/01 00:00:00','2019/01/02 15:00:00')
,(2,'2019/01/02 04:00:00','2019/01/03 15:00:00')
,(3,'2019/01/02 08:30:00','2019/01/02 15:00:00')
,(4,'2019/01/04 13:45:00','2019/01/07 15:30:00')
,(5,'2019/01/07 22:00:00','2019/02/03 15:00:00');

declare @EarliestStart datetime;
declare @LatestEnd datetime;

select @EarliestStart = min(StartDate)
      ,@LatestEnd = max(EndDate)
from @t;

declare @WorkStart time = '08:00';
declare @WorkEnd time = '18:00';


with n(n) as (select t from(values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(t))    -- Crete a tally table of numbers, by taking the ROW_NUMBER of 10 rows CROSS JOINed multiple times.  In this case 6 times for 10*10*10*10*10*10 = 1,000,000 potential rows
    ,m(m) as (select top(datediff(minute,@EarliestStart,@LatestEnd)+1) dateadd(minute,row_number() over (order by (select null))-1,@EarliestStart) from n n1,n n2,n n3,n n4,n n5,n n6)  -- and add that number as minutes to the minumum StartTime up to the maximum EndTime for a list of all potentially worked minutes
    ,w(w) as (select m from m where cast(m as time) >= @WorkStart and cast(m as time) < @WorkEnd)   -- then filter this list of minutes to just those that can be worked
select t.id
        ,t.StartDate
        ,t.EndDate
        ,count(w.w)/60. as WorkingHours
        ,count(w.w) as WorkingMinutes
from @t as t
    join w
        on t.StartDate <= w.w       -- JOIN onto the list of dates to get a row for each minute actually worked between each StartDate and EndDate, that can be COUNTed for total working time
            and t.EndDate > w.w
group by t.id
        ,t.StartDate
        ,t.EndDate
order by t.id
        ,t.StartDate
        ,t.EndDate;

输出

+----+-------------------------+-------------------------+--------------+----------------+
| id |        StartDate        |         EndDate         | WorkingHours | WorkingMinutes |
+----+-------------------------+-------------------------+--------------+----------------+
|  1 | 2019-01-01 00:00:00.000 | 2019-01-02 15:00:00.000 |    17.000000 |           1020 |
|  2 | 2019-01-02 04:00:00.000 | 2019-01-03 15:00:00.000 |    17.000000 |           1020 |
|  3 | 2019-01-02 08:30:00.000 | 2019-01-02 15:00:00.000 |     6.500000 |            390 |
|  4 | 2019-01-04 13:45:00.000 | 2019-01-07 15:30:00.000 |    31.750000 |           1905 |
|  5 | 2019-01-07 22:00:00.000 | 2019-02-03 15:00:00.000 |   267.000000 |          16020 |
+----+-------------------------+-------------------------+--------------+----------------+