我有两个日期表,我想加入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]
谢谢!
答案 0 :(得分:1)
编辑 - 看起来DateDiff方法可以使用索引,因为它不是包装值的标量函数。在我的环境中对测试数据进行快速比较表明,DateDiff的效率会提高几倍。
答案 1 :(得分:1)
比较效果
对我来说,使用2508条记录的数据集进行测试,日期均匀分布在一年内,并将表格自身加入,datepart
表现明显优于datediff
(datepart
之间的差异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
时间分别为:5ms
,4ms
,3432ms
。
那就是说,这只是对我设置的测试数据的测试...在不同的情况下可能会有很大差异。
索引数据怎么样?
填充数据后添加索引可提高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
更直观;也就是说,人们理解得更快。
datepart
和month
之间的选择,如果性能差异可以忽略不计,则应该符合您的其他要求和/或编码标准。
答案 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.