如何防止聚簇索引扫描?

时间:2017-04-20 17:30:40

标签: sql-server tsql sapb1

我在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是传递给函数的参数。

当我检查该功能的执行计划时,除了这件之外,一切看起来都很快。它给了我以下信息:

Clustered Index Scan

我在网上发现的关于如何预防或修复这种减速的所有来源建议添加索引,而不是引用某些列等,但由于我无法修改数据库,我一直在无法找到任何有关如何在我的情况下提供帮助的方法。

有什么建议吗?

编辑1:

从SQL Management

添加了表架构信息

Table Schema

编辑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

3 个答案:

答案 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&lt;br&gt;from   HLD1&lt;br&gt;WHERE  StrDate &gt;= @StrDate&lt;br&gt;AND    EndDate &lt; @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]&gt;=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]&lt;[@EndDate])) |      1 |      2 |      1 | Table Scan | Table Scan | OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1]), WHERE:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate]&gt;=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]&lt;[@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&lt;br&gt;from   HLD1&lt;br&gt;WHERE  StrDate &gt;= @StrDate&lt;br&gt;AND    EndDate &lt; @EndDate&lt;br&gt;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]&gt;=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]&lt;[@EndDate]) ORDERED FORWARD) |      1 |      3 |      2 | Index Scan   | Index Scan | OBJECT:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[id_hld1]),  WHERE:([fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[StrDate]&gt;=[@StrDate] AND [fiddle_9f66021924d842d39e112d909afc0794].[dbo].[HLD1].[EndDate]&lt;[@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;