效率:MONTH()与DATEDIFF()

时间:2017-02-16 16:53:23

标签: sql-server performance datediff datepart

我有两个日期表,我想加入INNER JOIN。 这些表格用FK相互连接,确保Tabla A上的记录及其表B中的相关记录在同一年。

长话短说 - 我想确保两个日期在同一个月。如上所述,DATEDIFF()在我的情况下没有逻辑优势 - 它永远不会给我-12或12,因为年份与等式无关。我的结果将始终与DATEDIFF或MONTH相同(当然我测试了它。)

有了这些假设 - 什么会更有效?

    SELECT .... 
    FROM DatesA da 
    INNER JOIN DatesB db 
    ON MONTH(da.Date) = MONTH(db.Date) 
    AND [Rest of the join]

    SELECT .... 
    FROM DatesA da 
    INNER JOIN DatesB db 
    ON DATEDIFF(MM, da.Date, db.Date) = 0 
    AND [Rest of the join]

谢谢!

3 个答案:

答案 0 :(得分:1)

编辑 - 看起来DateDiff方法可以使用索引,因为它不是包装值的标量函数。在我的环境中对测试数据进行快速比较表明,DateDiff的效率会提高几倍。

答案 1 :(得分:1)

比较效果

对我来说,使用2508条记录的数据集进行测试,日期均匀分布在一年内,并将表格自身加入,datepart表现明显优于datediffdatepart之间的差异1}}和month可以忽略不计,但datepart通常~1ms更快。此测试是在SQL 2008 R2 (SP3)完成的。完整代码分享如下:

--prep
create table #testDates (d date)

insert #testDates
select dateadd(dd,row_number() over (partition by 1 order by number) % 365,'2017-01-01')
from master.dbo.spt_values a --, master.dbo.spt_values --uncomment this for a larger test set

select @@VERSION --Microsoft SQL Server 2008 R2 (SP3) - 10.50.6529.0 (X64) 
go


--test statements
set statistics time on
select count(1) --return 1 so we're measuring query time; not the time to return the results
from #testDates a 
inner join #testDates b 
on month(a.d) = month(b.d)
set statistics time off

set statistics time on
select count(1) 
from #testDates a 
inner join #testDates b 
on datepart(month,a.d) = datepart(month,b.d)
set statistics time off

set statistics time on
select count(1) 
from #testDates a 
inner join #testDates b 
on datediff(MM,a.d,b.d) = 0
set statistics time off

--cleanup
go
drop table #testDates 

时间分别为:5ms4ms3432ms

那就是说,这只是对我设置的测试数据的测试...在不同的情况下可能会有很大差异。

索引数据怎么样?

填充数据后添加索引可提高datediff的性能;虽然只到3390ms;仍然远远落后于其他人。

create index ix_testDates_d on #testDates(d) --create the index after populating the data to ensure it's not fragmented

其他

  • 使用datepart / month而不是datediff的另一个原因是这是更好的自我记录代码;即它显示您正在寻找同月的日期;而不是它们之间的月数为0的日期(这是相同的事情(除了数年);但后者需要花费更多时间来进行认知处理。

  • 使用datepart而不是month的原因是datepart符合ANSI标准。

  • 但是month优于datepart作为确定性函数(参考:https://stackoverflow.com/a/14851564/361842),由于某种原因datepart不是!

  • 此外month更直观;也就是说,人们理解得更快。

  • datepartmonth之间的选择,如果性能差异可以忽略不计,则应该符合您的其他要求和/或编码标准。

答案 2 :(得分:1)

我的答案基于@JohnLBevan先前的回答

这只差1ms。它是sergable soltion并使用日期列中的索引。

“诀窍”是先前有一种日历表(我即时创建),每个月的第一天和最后一天。

create table #testDates (d date)

insert #testDates
select dateadd(dd,row_number() over (partition by 1 order by number) % 365,'2017-01-01')
from master.dbo.spt_values a --, master.dbo.spt_values --uncomment this for a larger test set

select @@VERSION --Microsoft SQL Server 2008 R2 (SP3) - 10.50.6529.0 (X64) 
go


create index ix_testDates_d on #testDates(d) 

--test statements
set statistics time on
select count(1) --return 1 so we're measuring query time; not the time to return the results
from #testDates a 
inner join #testDates b 
on month(a.d) = month(b.d)
set statistics time off

select min(d) iniDay,max(d) endDay into #months from #testDates
group by month(d)


set statistics time on
select count(1) --return 1 so we're measuring query time; not the time to return the results
from #testDates a 
inner join #months m
on a.d>= m.iniDay and a.d<=m.endDay
inner join #testDates b 
 on b.d>= m.iniDay and b.d<=m.endDay
set statistics time off


--cleanup
go
drop table #testDates 
drop table #months

时间为4毫秒,日历表为10毫秒,1毫秒。

150.000行

(150000 row(s) affected)

(1 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 4 ms.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 141 ms,  elapsed time = 130 ms.

(12 row(s) affected)
SQL Server parse and compile time: 
   CPU time = 14 ms, elapsed time = 14 ms.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 47 ms,  elapsed time = 48 ms.