1

使用 SQL Server 2016。

我有一个存储过程,可以针对一系列日期生成选项列表。为了清楚起见,针对几天的运输选项,但对这里的细节并不重要。

存储过程的第一步会生成一个日期列表以存储其他数据,并且生成此列表所花费的时间比代码的余额要长得多。虽然这个过程很短,但调用次数意味着这段代码使系统承受的负载比其他任何东西都多。

考虑到这一点,我一直在测试几个选项的效率。

迭代公用表表达式:

CREATE FUNCTION [dbo].[udf_DateRange_CTE] (@StartDate DATE,@EndDate DATE)
RETURNS @Return TABLE (Date DATE NOT NULL)
AS
    BEGIN
        WITH    dates(date)
                  AS (SELECT    @StartDate [Date]
                      UNION ALL
                      SELECT    DATEADD(dd, 1, [Date])
                      FROM      dates
                      WHERE     [Date] < @EndDate
                     )
            INSERT  INTO @Return 
            SELECT  date
            FROM    dates
            OPTION  (MAXRECURSION 0)
        RETURN 
    END

一个while循环:

CREATE FUNCTION [dbo].[udf_DateRange_While] (@StartDate DATE,@EndDate DATE)
RETURNS @Retun TABLE (Date DATE NOT NULL,PRIMARY KEY (Date))
AS
    BEGIN
        WHILE @StartDate <= @EndDate
            BEGIN
                INSERT  INTO @Retun
                VALUES  (@StartDate)
                SET @StartDate = DATEADD(DAY,1,@StartDate)
            END
        RETURN 
    END

从预先填充的日期表中查找:

CREATE FUNCTION [dbo].[udf_DateRange_query] (@StartDate DATE,@EndDate DATE)
RETURNS @Return TABLE (Date DATE NOT NULL)
AS
    BEGIN
        INSERT  INTO @Return
        SELECT  Date
        FROM    DateLookup
        WHERE   Date >= @StartDate
                AND Date <= @EndDate
        RETURN 
    END

在效率方面,我进行了 1000 次测试,生成了一年的日期,结果如下:

  • CTE:10.0 秒
  • 时间:7.7 秒
  • 查询:2.6 秒

从这一点来看,查询绝对是更快的选择,但确实需要一个需要创建和维护的永久日期表。这意味着查询不再是“独立的”,并且可以请求给定日期范围之外的日期。

有谁知道为某个范围生成日期的任何更有效的方法,或者我可以应用于上述任何优化?

非常感谢。

4

1 回答 1

2

您可以尝试如下。这应该是快速比较CTEWHILE循环。

DECLARE @StartDate DATETIME = Getdate() - 1000 
DECLARE @EndTime DATETIME = Getdate() 

SELECT * 
FROM   (SELECT @StartDate + RN AS DATE 
        FROM   (SELECT ROW_NUMBER() 
                         OVER ( 
                           ORDER BY (SELECT NULL)) RN 
                FROM   master..[spt_values]) T) T1 
WHERE  T1.DATE <= @EndTime 
ORDER  BY DATE 

注意:这适用于日差 <= 2537 天

如果要支持更多范围,可以使用CROSS JOINonmaster..[spt_values]生成 0 - 6436369 天之间的范围,如下所示。

DECLARE @StartDate DATETIME = Getdate() - 10000
DECLARE @EndTime DATETIME = Getdate() 
SELECT @StartDate + RN AS DATE FROM
(   
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN 
    FROM   master..[spt_values] T1
    CROSS JOIN  master..[spt_values] T2
) T 
WHERE RN <= DATEDIFF(DAY,@StartDate,@EndTime)
于 2018-04-03T08:53:39.890 回答