SQL 服务器 - 有效生成范围内的日期

SQL Server - Efficient generation of dates in a range

使用 SQL 服务器 2016。

我有一个存储过程,它生成一个日期范围内的选项列表。为了清楚起见,针对天数的运输选项,但对此处的具体细节并不重要。

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

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

迭代常用table表达式:

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

从预填充的 table 日期中查找:

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 次并得到以下结果:

由此看来,查询绝对是更快的选择,但确实需要永久 table 需要创建和维护的日期。这意味着该查询并不孤单 "self-contained" 并且可以请求给定日期范围之外的日期。

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

非常感谢。

您可以像下面这样尝试。与 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 天

如果您想支持更多范围,您可以在 master..[spt_values] 上使用 CROSS JOIN 来生成 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)