Sql server 请评论我的脚本-如何使它更有效

Sql server 请评论我的脚本-如何使它更有效,sql-server,tsql,Sql Server,Tsql,我有一个表SYS_Holidays,它有每个假期的开始和结束日期。我需要以关系形式输出所有假日日期。例如,我将2017年12月25日至2018年1月2日作为一行输入,我想输出2017年12月25日、2018年12月26日。。。至1月2日,共9行 我已经写了这个脚本,你能告诉我如何使它更有效率吗 SELECT H.HolidayName , DATEADD(DAY, Number-1, H.StartDate) AS HolidayDate FROM SYS_Holid

我有一个表SYS_Holidays,它有每个假期的开始和结束日期。我需要以关系形式输出所有假日日期。例如,我将2017年12月25日至2018年1月2日作为一行输入,我想输出2017年12月25日、2018年12月26日。。。至1月2日,共9行

我已经写了这个脚本,你能告诉我如何使它更有效率吗

SELECT 
    H.HolidayName
    , DATEADD(DAY, Number-1, H.StartDate) AS HolidayDate
FROM 
    SYS_Holidays AS H
    CROSS JOIN Config_Numbers AS N 
WHERE 
    -- Figure the # of days between start and end: one row for each holiday-date
    -- If EndDate is null, just use StartDate (i.e. 1-day holiday)
    N.Number <= DATEDIFF(DAY, H.StartDate, ISNULL(H.EndDate, H.StartDate) ) + 1 

注意:Config_Numbers是我创建的一个表,其中包含大量的整数列表,如BIGINT,它可以使用日期表和内部联接来完成。如果子查询效率不够,请使用该子查询生成表:

Create table #Test (HolidayName nvarchar(100), StartDate Date, EndDate Date)

Insert Into #Test Values ('Christmas', '2017-12-22', '2018-01-03'), ('Easter' , '2017-04-10', '2017-04-16')

SELECT HolidayName, DatesList.[Date] as HolidayDate
FROM #Test t
inner join (
    SELECT cast(dateadd(day, number, '2017-1-1') as date) as [Date]
     FROM master..spt_values WHERE type='P' AND number < 1000) AS DatesList 
        on t.StartDate<=DatesList.[Date] and t.EndDate>=DatesList.[Date]

我修改了@cloudsafe的答案,以产生下面的代码。它仍然比任何使用配置号的连接都要快得多。子树成本约为0.2785

我认为2048可以覆盖5年多一点的时间,所以我把我的代码分成了5年的代码块,并建立了一个联盟来加入它们

问题是,我必须记住每5年再做一次工会:-

SELECT HolidayName, DatesList.[Date] as HolidayDate
FROM SYS_Holidays AS H
inner join (
    SELECT cast(dateadd(day, number, '2013-01-01') as date) as [Date]
     FROM master..spt_values WHERE type='P' AND number < 2048) AS DatesList 
        on H.StartDate <= DatesList.[Date] and H.EndDate >=DatesList.[Date]

UNION

SELECT HolidayName, DatesList.[Date] as HolidayDate, H.HolidayId, H.CampusId, H.CategoryId
FROM SYS_Holidays AS H
inner join (
    SELECT cast(dateadd(day, number, '2018-01-01') as date) as [Date]
     FROM master..spt_values WHERE type='P' AND number < 2048) AS DatesList 
        on H.StartDate <= DatesList.[Date] and H.EndDate >=DatesList.[Date]

有进一步的改进建议吗?

BIGINT?除非你的数字表真的包含超过20亿个数字,否则这是不必要的,如果它包含超过20亿个数字,那就太多了。就你的目的而言,如果你的查询从未跨越一年的界限,即使1000也可以;在几乎所有可以实际使用数字表的情况下,1M就足够了。至少,我应该把它的主键放在N上。是吗?为什么是交叉连接而不是内部连接?我想优化器可能会以同样的计划结束,但我至少会尝试将其作为steadNote的内部连接,如果我们谈论公共假日,那么他的方法一开始就不必要的花哨。只有少数几个假期是多天的,对于那些多天的假期来说,给每个日期指定自己的一行几乎不是一种强迫。由于某些节日每年都会改变其位置,例如复活节,因此每年都有不同日期的日期表几乎是不可避免的。对于查询而言,具有唯一日期的表是最有效的。@Jeroenmoster:是的,它的主键是N.Number,感谢您的建议,我现在将其降级为INT。最大的数字是3M。出于某种原因,尝试从配置号中执行删除,其中编号>10485756;不会减少它,也不会抛出任何错误消息。知道为什么吗?可能是因为10485756大于300万-这里不需要二进制数,这样的表应该用于人类编写的查询中。一百万就够了。非常有趣的方法。。。同一表格SYS_Holidays的子树成本大幅降低:0.0643-ish。不需要使用配置号。但是,master..spt_值的上限为2048。关于如何将其提高到6000会更好吗?那么,我应该在什么时候使用我自己的数字表,例如上面的配置数字,什么时候使用master..spt_值,而不是2048的明显限制?@Muhammad可以更改子查询,选择castdateaddday,数字*10+n,'2017-1-1'作为[日期]从master..spt_值交叉连接值0,1,2,3,4,5,6,7,8,9,其中type='P'和number<20000@Muhammad您的数字表可以替换master..spt_值,其中type='P'和number<1000这里有一个:不要使用spt_值,使用您自己的数字表。一方面,spt_值没有文档记录,另一方面,执行跨数据库查询会占用您不想要的锁。如果您确实不想要数字表,那么动态递归CTE是另一种选择,但是数字表通常会提供更好的性能。