执行我当前的查询需要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
答案 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 |
+----+-------------------------+-------------------------+--------------+----------------+