查询需要太长时间的功能

问题描述 投票:3回答:2

执行当前查询需要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 @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)
             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

如何在不使用查询中的函数的情况下运行查询?我已经尝试了很多东西,比如索引,但是索引甚至需要更长的时间。请帮助我们,并记住我是一个新手与sql等。

非常感谢,Shabby

sql tsql
2个回答
0
投票

当然那会很慢。它必须将该函数应用于表中的每一行。它不能使用索引来最小化它必须处理的行数。

粗略的选择是“手动”限制它必须处理的行数。比如知道从“现在”回来的1小时工作时间必须至少1小时前,也许你甚至可以“知道”门票永远不会超过10天?

现在你可以......

WHERE
        [plugin.tickets].[Ticket].Created >= DATEADD(DAY , -10, GETDATE())
    AND [plugin.tickets].[Ticket].Created <  DATEADD(Hour, -1 , GETDATE())
    AND [plugin.tickets].[Ticket].status <= 2
    AND [dbo].[worktime]([plugin.tickets].[Ticket].Created, GetDate()) >= 1

然后可以使用索引快速解决前三个条件(在(status, created)上创建索引,作为单个复合索引),减少必须通过函数解析的记录数。

更好的是,写一个dateadd函数......

WHERE
        [plugin.tickets].[Ticket].status  <= 2
    AND [plugin.tickets].[Ticket].created <= [dbo].[add_worktime]('HOUR', -1, GetDate())

现在,您的函数仅被称为ONCE(使用GETDATE()作为输入)而不是每行重复一次。并且它的结果可以用于与前面提到的相同的索引。


0
投票

我百分百肯定你的查询很慢,因为:

WHILE(@CurrentDate<=@LastDate)
    BEGIN     
        IF
             (DATEPART(dw, @CurrentDate)!=1 AND DATEPART(dw, @CurrentDate)!=7)
                 AND @CurrentDate NOT IN 
                     (SELECT Datum_feestdag FROM Feestdagen)

因此,为了改善这一点,我建议你在Datum_feestdag上创建Feestdagen的索引,并写一个像sargeable查询。

IF (DATEPART(dw, @CurrentDate)!=1 AND DATEPART(dw, @CurrentDate)!=7)
        AND NOT EXISTS (SELECT Datum_feestdag 
                        FROM Feestdagen
                        WHERE @CurrentDate = Datum_feestdag)
© www.soinside.com 2019 - 2024. All rights reserved.