我在SAP B1数据库中运行,因此不允许修改数据库的结构。
我有一个包含4列的表格。
Table name: HLD1
Column Name Type
1 HldCode nvarchar
2 StrDate datetime
3 EndDate datetime
4 Rmrks nvarchar
有些数据如下:
HldCode StrDate EndDate Rmrks
2016 Holidays 2016-09-05 00:00:00.000 2016-09-05 00:00:00.000 Labor Day
2016 Holidays 2016-11-24 00:00:00.000 2016-11-25 00:00:00.000 Thankgiving
2016 Holidays 2016-12-26 00:00:00.000 2016-12-26 00:00:00.000 Christmas
2017 Holidays 2017-01-02 00:00:00.000 2017-01-02 00:00:00.000 New Years Day
2017 Holidays 2017-05-29 00:00:00.000 2017-05-29 00:00:00.000 Memorial Day
2017 Holidays 2017-07-04 00:00:00.000 2017-07-04 00:00:00.000 Indepenance Day
请注意,此表中没有主键。
我创建了一个函数来查找两个日期之间的天数,不包括假期(由上面的HLD1表提供)和周末。虽然该函数按预期工作,但每行使用它还需要大约0.75秒,并且我们尝试返回50000行以便稍后在Crystal Reports中进行汇总。
引用HLD1表的函数(并在执行计划中导致聚簇索引)如下所示:
CREATE FUNCTION [dbo].[dateDiffHolidays] (
declare @START DATE
declare @END DATE
)
RETURNS INT
AS
BEGIN
SELECT @AddDays =
(select sum(datediff(dd,strdate,enddate) + 1) from hld1
where strdate between @START and @END)
+
(SELECT
(DATEDIFF(wk, @Start, @End) * 2)
+(CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END)
+(CASE WHEN DATENAME(dw, @End) = 'Saturday' THEN 1 ELSE 0 END))
RETURN @AddDays
END
GO
具体来说,第一部分。 @START
和@END
是传递给函数的参数。
当我检查该功能的执行计划时,除了这件之外,一切看起来都很快。它给了我以下信息:
我在网上发现的关于如何预防或修复这种减速的所有来源建议添加索引,而不是引用某些列等,但由于我无法修改数据库,我一直在无法找到任何有关如何在我的情况下提供帮助的方法。
有什么建议吗?
编辑1:
从SQL Management
添加了表架构信息编辑2:
添加了函数的全文,以防万一:
CREATE FUNCTION [dbo].[dateDiffHolidays] (
@startdaytime DATETIME,
@enddaytime DATETIME
)
RETURNS INT
AS
BEGIN
DECLARE @answer INT, @START Date, @END Date, @AddDays int
SET @answer = 0
-- Strip Times
SELECT @START = dateadd(dd,0, datediff(dd,0,@StartDayTime)), @END =
dateadd(dd,0, datediff(dd,0,@EndDayTime))
SELECT @AddDays = (select sum(datediff(dd,strdate,enddatE) + 1) from hld1
where strdate between @START and @END
order by HldCode, StrDate, EndDate) + (
SELECT
(DATEDIFF(wk, @Start, @End) * 2)
+(CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END)
+(CASE WHEN DATENAME(dw, @End) = 'Saturday' THEN 1 ELSE 0 END))
-- handle end conditions
DECLARE @firstWeekDayInRange datetime, @lastWeekDayInRange datetime;
SELECT @firstWeekDayInRange = @START, @lastWeekDayInRange = @END
WHILE @firstWeekDayInRange in (select cast( DATEADD(day, t.N - 1, StrDate)
as date) as ResultDate
from HLD1 s join cteTally t on t.N <= DATEDIFF(day, StrDate, EndDate) + 1)
or datepart(dw,@firstWeekDayInRange) in (1,7)
BEGIN
SELECT @firstWeekDayInRange =
CASE
WHEN @firstWeekDayInRange in (select cast( DATEADD(day, t.N - 1, StrDate) as
date) from HLD1 s join cteTally t on t.N <= DATEDIFF(day, StrDate, EndDate)
+ 1)
or datepart(dw,@firstWeekDayInRange) in (1,7)
THEN dateadd(DAY,1,@firstWeekDayInRange)
ELSE @firstWeekDayInRange
END
END
WHILE @lastWeekDayInRange in (select cast( DATEADD(day, t.N - 1, StrDate) as
date) as ResultDate
from HLD1 s join cteTally t on t.N <= DATEDIFF(day, StrDate, EndDate) + 1)
or datepart(dw,@lastWeekDayInRange) in (1,7)
BEGIN
SELECT @lastWeekDayInRange =
CASE
WHEN @lastWeekDayInRange in (select cast( DATEADD(day, t.N - 1, StrDate) as
date) from HLD1 s join cteTally t on t.N <= DATEDIFF(day, StrDate, EndDate)
+ 1)
or datepart(dw,@lastWeekDayInRange) in (1,7)
THEN dateadd(DAY,-1,@lastWeekDayInRange)
ELSE @lastWeekDayInRange
END
END
-- add one day to answer (to count Friday) if enddate was on a weekend
SELECT @answer = @answer +
CASE
-- triggered if start and end date are on same weekend
WHEN dateDiff(DAY,@firstWeekDayInRange,@lastWeekDayInRange) < 0 THEN
(@answer * -1)
-- otherwise count the days and substract 2 days per weekend in between dates
ELSE (DateDiff(DAY, @firstWeekDayInRange, @lastWeekDayInRange) - @AddDays)
END
RETURN @answer
END
GO
答案 0 :(得分:2)
您可以尝试添加ORDER BY
子句。
CREATE TABLE HLD1
(
HldCode nvarchar(20),
StrDate datetime,
EndDate datetime,
Rmrks nvarchar(50)
)
create unique index id_hld1 on HLD1 (HldCode, StrDate, EndDate);
GO
INSERT INTO HLD1
VALUES ('2016 Holidays', '2016-09-05 00:00:00.000', '2016-09-05 00:00:00.000', 'Labor Day'),
('2016 Holidays', '2016-11-24 00:00:00.000', '2016-11-25 00:00:00.000', 'Thanksgiving'),
('2016 Holidays', '2016-12-26 00:00:00.000', '2016-12-26 00:00:00.000', 'Christmas'),
('2017 Holidays', '2017-01-02 00:00:00.000', '2017-01-02 00:00:00.000', 'New Years Day'),
('2017 Holidays', '2017-05-29 00:00:00.000', '2017-05-29 00:00:00.000', 'Memorial Day'),
('2017 Holidays', '2017-07-04 00:00:00.000', '2017-07-04 00:00:00.000', 'Independence Day');
GO
6 rows affected
DECLARE @StrDate datetime = '2017-01-01';
DECLARE @EndDate datetime = '2018-01-01'
set statistics profile on;
SELECT HldCode, StrDate, EndDate, Rmrks
FROM HLD1
WHERE StrDate >= @StrDate
AND EndDate < @EndDate;
set statistics profile off;
GO
输出:
HldCode | StrDate | EndDate | Rmrks
:------------ | :------------------ | :------------------ | :--------------
2017 Holidays | 02/01/2017 00:00:00 | 02/01/2017 00:00:00 | New Years Day
2017 Holidays | 29/05/2017 00:00:00 | 29/05/2017 00:00:00 | Memorial Day
2017 Holidays | 04/07/2017 00:00:00 | 04/07/2017 00:00:00 | Indepenance Day
Rows | Executes | StmtText | StmtId | NodeId | Parent | PhysicalOp | LogicalOp | Argument | DefinedValues | EstimateRows | EstimateIO | EstimateCPU | AvgRowSize | TotalSubtreeCost | OutputList | Warnings | Type | Parallel | EstimateExecutions
> :--- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -----: | -----: | -----: | :--------- | :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------- | :--------- | :---------- | ---------: | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------- | :------- | :-----------------
> 3 | 1 | SELECT HldCode, StrDate, EndDate, Rmrks<br>from HLD1<br>WHERE StrDate >= @StrDate<br>AND EndDate < @EndDate | 1 | 1 | 0 | <em>null</em> | <em>null</em> | <em>null</em> | <em>null</em> | 1 | <em>null</em> | <em>null</em> | <em>null</em> | 0.0032886 | <em>null</em> | <em>null</em> | SELECT | False | <em>null</em>
> 3 | 1 | |--Table Scan(OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1]), WHERE:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate]>=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]<[@EndDate])) | 1 | 2 | 1 | Table Scan | Table Scan | OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1]), WHERE:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate]>=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]<[@EndDate]) | [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[HldCode], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[Rmrks] | 1 | 0.003125 | 0.0001636 | 99 | 0.0032886 | [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[HldCode], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[Rmrks] | <em>null</em> | PLAN_ROW | False | 1
DECLARE @StrDate datetime = '2017-01-01';
DECLARE @EndDate datetime = '2018-01-01'
set statistics profile on;
SELECT HldCode, StrDate, EndDate, Rmrks
FROM HLD1
WHERE StrDate >= @StrDate
AND EndDate < @EndDate
ORDER BY HldCode, StrDate, EndDate;
set statistics profile off;
GO
输出:
HldCode | StrDate | EndDate | Rmrks
:------------ | :------------------ | :------------------ | :--------------
2017 Holidays | 02/01/2017 00:00:00 | 02/01/2017 00:00:00 | New Years Day
2017 Holidays | 29/05/2017 00:00:00 | 29/05/2017 00:00:00 | Memorial Day
2017 Holidays | 04/07/2017 00:00:00 | 04/07/2017 00:00:00 | Indepenance Day
Rows | Executes | StmtText | StmtId | NodeId | Parent | PhysicalOp | LogicalOp | Argument | DefinedValues | EstimateRows | EstimateIO | EstimateCPU | AvgRowSize | TotalSubtreeCost | OutputList | Warnings | Type | Parallel | EstimateExecutions
:--- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -----: | -----: | -----: | :----------- | :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------- | :--------- | :---------- | ---------: | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------- | :------- | :-----------------
3 | 1 | SELECT HldCode, StrDate, EndDate, Rmrks<br>from HLD1<br>WHERE StrDate >= @StrDate<br>AND EndDate < @EndDate<br>ORDER BY HldCode, StrDate, EndDate | 1 | 1 | 0 | <em>null</em> | <em>null</em> | <em>null</em> | <em>null</em> | 1 | <em>null</em> | <em>null</em> | <em>null</em> | 0.00658116 | <em>null</em> | <em>null</em> | SELECT | False | <em>null</em>
3 | 1 | |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000])) | 1 | 2 | 1 | Nested Loops | Inner Join | OUTER REFERENCES:([Bmk1000]) | <em>null</em> | 1 | 0 | 4.18E-06 | 99 | 0.00658116 | [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[HldCode], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[Rmrks] | <em>null</em> | PLAN_ROW | False | 1
3 | 1 | |--Index Scan(OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[id_hld1]), WHERE:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate]>=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]<[@EndDate]) ORDERED FORWARD) | 1 | 3 | 2 | Index Scan | Index Scan | OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[id_hld1]), WHERE:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate]>=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]<[@EndDate]) ORDERED FORWARD | [Bmk1000], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[HldCode], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate] | 1 | 0.003125 | 0.0001636 | 55 | 0.0032886 | [Bmk1000], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[HldCode], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate], [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate] | <em>null</em> | PLAN_ROW | False | 1
3 | 3 | |--RID Lookup(OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD) | 1 | 5 | 2 | RID Lookup | RID Lookup | OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD | [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[Rmrks] | 1 | 0.003125 | 0.0001581 | 61 | 0.0032831 | [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[Rmrks] | <em>null</em> | PLAN_ROW | False | 1
dbfiddle here
<强>更新强>
只要您需要存储过程,就可以尝试;
WITH (INDEX(IndexName))
CREATE FUNCTION [dbo].[dateDiffHolidays] (@START DATE, @END DATE) RETURNS INT AS BEGIN DECLARE @AddDays int; SELECT @AddDays = (SELECT sum(datediff(dd, StrDate, EndDate) + 1) FROM hld1 WITH (INDEX(HLD1_PRIMARY)) WHERE StrDate BETWEEN @START AND @END) + (SELECT (DATEDIFF(wk, @Start, @End) * 2) + (CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END) + (CASE WHEN DATENAME(dw, @End) = 'Saturday' THEN 1 ELSE 0 END)) RETURN @AddDays END
DECLARE @StrDate datetime = '2017-01-01'; DECLARE @EndDate datetime = '2018-01-01'; DECLARE @NumDays int = 0; set statistics profile on; EXEC @NumDays = [dbo].[dateDiffHolidays] @StrDate, @EndDate; set statistics profile off; SELECT @NumDays;
Rows | Executes | StmtText | StmtId | NodeId | Parent | PhysicalOp | LogicalOp | Argument | DefinedValues | EstimateRows | EstimateIO | EstimateCPU | AvgRowSize | TotalSubtreeCost | OutputList | Warnings | Type | Parallel | EstimateExecutions :--- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -----: | -----: | -----: | :--------------- | :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------- | :--------- | :---------- | ---------: | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------- | :------- | :------- | :------- | :----------------- 1 | 1 | SELECT @AddDays = (SELECT sum(datediff(dd, StrDate, EndDate) + 1) <br> FROM hld1 WITH (INDEX(HLD1_PRIMARY))<br> WHERE StrDate BETWEEN @START AND @END) <br> + <br> (SELECT (DATEDIFF(wk, @Start, @End) * 2)<br> + (CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END)<br> + (CASE WHEN DATENAME(dw, @End) = 'Saturday' THEN 1 ELSE 0 END)) | 1 | 1 | 0 | null | null | null | null | 1 | null | null | null | 0.00329658 | null | null | SELECT | False | null 0 | 0 | |--Compute Scalar(DEFINE:([Expr1006]=[Expr1003]+(datediff(week,CONVERT_IMPLICIT(datetimeoffset(7),[@START],0),CONVERT_IMPLICIT(datetimeoffset(7),[@END],0))*(2)+CASE WHEN datename(weekday,[@START])=N'Sunday' THEN (1) ELSE (0) END+CASE WHEN datename(weekday,[@END])=N'Saturday' THEN (1) ELSE (0) END))) | 1 | 2 | 1 | Compute Scalar | Compute Scalar | DEFINE:([Expr1006]=[Expr1003]+(datediff(week,CONVERT_IMPLICIT(datetimeoffset(7),[@START],0),CONVERT_IMPLICIT(datetimeoffset(7),[@END],0))*(2)+CASE WHEN datename(weekday,[@START])=N'Sunday' THEN (1) ELSE (0) END+CASE WHEN datename(weekday,[@END])=N'Saturday' THEN (1) ELSE (0) END)) | [Expr1006]=[Expr1003]+(datediff(week,CONVERT_IMPLICIT(datetimeoffset(7),[@START],0),CONVERT_IMPLICIT(datetimeoffset(7),[@END],0))*(2)+CASE WHEN datename(weekday,[@START])=N'Sunday' THEN (1) ELSE (0) END+CASE WHEN datename(weekday,[@END])=N'Saturday' THEN (1) ELSE (0) END) | 1 | 0 | 1E-07 | 11 | 0.00329658 | [Expr1006] | null | PLAN_ROW | False | 1 0 | 0 | |--Compute Scalar(DEFINE:([Expr1003]=CASE WHEN [Expr1012]=(0) THEN NULL ELSE [Expr1013] END)) | 1 | 3 | 2 | Compute Scalar | Compute Scalar | DEFINE:([Expr1003]=CASE WHEN [Expr1012]=(0) THEN NULL ELSE [Expr1013] END) | [Expr1003]=CASE WHEN [Expr1012]=(0) THEN NULL ELSE [Expr1013] END | 1 | 0 | 0 | 11 | 0.00329648 | [Expr1003] | null | PLAN_ROW | False | 1 1 | 1 | |--Stream Aggregate(DEFINE:([Expr1012]=COUNT_BIG([Expr1007]), [Expr1013]=SUM([Expr1007]))) | 1 | 4 | 3 | Stream Aggregate | Aggregate | null | [Expr1012]=COUNT_BIG([Expr1007]), [Expr1013]=SUM([Expr1007]) | 1 | 0 | 2.3E-06 | 11 | 0.00329648 | [Expr1012], [Expr1013] | null | PLAN_ROW | False | 1 0 | 0 | |--Compute Scalar(DEFINE:([Expr1007]=datediff(day,[fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate],[fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[EndDate])+(1))) | 1 | 5 | 4 | Compute Scalar | Compute Scalar | DEFINE:([Expr1007]=datediff(day,[fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate],[fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[EndDate])+(1)) | [Expr1007]=datediff(day,[fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate],[fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[EndDate])+(1) | 3 | 0 | 3E-07 | 11 | 0.00329418 | [Expr1007] | null | PLAN_ROW | False | 1 3 | 1 | |--Index Scan(OBJECT:([fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[HLD1_PRIMARY]), WHERE:([fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate]>=[@START] AND [fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate]<=[@END])) | 1 | 6 | 5 | Index Scan | Index Scan | OBJECT:([fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[HLD1_PRIMARY]), WHERE:([fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate]>=[@START] AND [fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate]<=[@END]), FORCEDINDEX | [fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate], [fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[EndDate] | 3 | 0.003125 | 0.0001636 | 23 | 0.0032886 | [fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[StrDate], [fiddle_c7abc2eb9b3f49599be6803069c6aa56].[dbo].[HLD1].[EndDate] | null | PLAN_ROW | False | 1 | (No column name) | | ---------------: | | 108 |
dbfiddle here
答案 1 :(得分:0)
由于HLD1_PRIMARY
索引包含以下列:HldCode, StrDate, EndDate
尝试添加按HldCode
过滤到您的聚合选择的条件。
例如,如果您只想包含HldCode = '2016 Holidays'
和HldCode = '2017 Holidays'
的行:
CREATE FUNCTION [dbo].[dateDiffHolidays] (
declare @START DATE
declare @END DATE
)
RETURNS INT
AS
BEGIN
SELECT @AddDays = (
select
sum(datediff(dd,strdate,enddate) + 1)
from
hld1
where
HldCode in ('2016 Holidays', '2017 Holidays')
and strdate between @START and @END
)
+
(
SELECT
(DATEDIFF(wk, @Start, @End) * 2)
+(CASE WHEN DATENAME(dw, @Start) = 'Sunday' THEN 1 ELSE 0 END)
+(CASE WHEN DATENAME(dw, @End) = 'Saturday' THEN 1 ELSE 0 END)
)
RETURN @AddDays
END
<强>更新强>
对于该特定查询,您不会比索引搜索更好。
然后,在查看完整代码之后,我怀疑问题不在于该查询,而是在用于计算@firstWeekDayInRange
和@lastWeekDayInRange
的while循环上:
WHILE @firstWeekDayInRange in (
select
cast(DATEADD(day, t.N - 1, StrDate) as date) as ResultDate
from
HLD1 s
join cteTally t
on t.N <= DATEDIFF(day, StrDate, EndDate) + 1
)
or datepart(dw, @firstWeekDayInRange) in (1,7)
BEGIN
SELECT @firstWeekDayInRange =
CASE
WHEN @firstWeekDayInRange in (
select
cast(DATEADD(day, t.N - 1, StrDate) as date)
from
HLD1 s
join cteTally t on
t.N <= DATEDIFF(day, StrDate, EndDate) + 1
)
or datepart(dw,@firstWeekDayInRange) in (1,7) THEN
dateadd(DAY,1,@firstWeekDayInRange)
ELSE
@firstWeekDayInRange
END
END
这些查询最好会导致聚集索引扫描,最坏的情况是HLD1表上的表扫描,以及循环的每次迭代,我们对cteTally不太了解,所以情况会更糟。
答案 2 :(得分:0)
你必须使用一个功能吗?如何创建日期日历类表?
CREATE TABLE #Datecalendar
(DateId DATE PRIMARY KEY
, IsWeekend BIT DEFAULT 0
, IsHoliday BIT DEFAULT 0
);
CREATE TABLE #HLD1
(HldCode nvarchar(20)
, StrDate datetime
, EndDate datetime
, Rmrks nvarchar(50)
);
INSERT INTO #HLD1
VALUES ('2016 Holidays', '2016-09-05 00:00:00.000', '2016-09-05 00:00:00.000', 'Labor Day'),
('2016 Holidays', '2016-11-24 00:00:00.000', '2016-11-25 00:00:00.000', 'Thanksgiving'),
('2016 Holidays', '2016-12-26 00:00:00.000', '2016-12-26 00:00:00.000', 'Christmas'),
('2017 Holidays', '2017-01-02 00:00:00.000', '2017-01-02 00:00:00.000', 'New Years Day'),
('2017 Holidays', '2017-05-29 00:00:00.000', '2017-05-29 00:00:00.000', 'Memorial Day'),
('2017 Holidays', '2017-07-04 00:00:00.000', '2017-07-04 00:00:00.000', 'Independence Day');
WITH cte AS (SELECT CAST('2016-01-01' AS DATE) AS DateId
UNION ALL
SELECT DATEADD(dd, 1, DateId)
FROM cte
WHERE DATEADD(dd, 1, DateId) <= '2019-01-01'
)
INSERT INTO #Datecalendar
(DateId
, IsWeekend
, IsHoliday
)
SELECT DateId
,CASE WHEN DATEPART(WEEKDAY,DateId) =1 OR DATEPART(WEEKDAY,DateId) = 7 THEN 1 ELSE 0 END
,CASE WHEN h.HldCode IS NOT NULL THEN 1 ELSE 0 END
FROM cte cte
LEFT JOIN #HLD1 h
ON cte.DateId BETWEEN h.StrDate AND h.EndDate
OPTION (MAXRECURSION 0);
SELECT COUNT(*)
FROM #Datecalendar
WHERE DateId BETWEEN '2016-05-06' AND '2017-02-24'
AND IsWeekend = 0
AND IsHoliday = 0;
DROP TABLE #HLD1;
DROP TABLE #Datecalendar;