ste*_*rgh 5 sql-server datetime sql-server-2012
我有一个返回几千个记录的查询,连接在几个表中.在WHERE子句中,过去检查日期不超过两个月.首先,查询将此日期边界设置为变量,并使用WHERE.
DECLARE @startdate as DATE = DATEADD(MONTH, -2, SYSDATETIME())
select [....]
where dateinquestion >= @startdate
Run Code Online (Sandbox Code Playgroud)
这运行得很好(返回4秒内预期的结果),但我想摆脱变量声明并将赋值移动到WHERE子句本身:
select [....]
where dateinquestion >= DATEADD(MONTH, -2, SYSDATETIME())
Run Code Online (Sandbox Code Playgroud)
这运行超过一分钟,吃掉所有CPU.我终止了查询以停止推送服务器,没有给出结果.更改为GETDATE()(我不需要来自SYSDATETIME()的精度)加快速度:
select [....]
where dateinquestion >= DATEADD(MONTH, -2, GETDATE())
Run Code Online (Sandbox Code Playgroud)
结果与方案1类似.
我相信这是因为SYSDATETIME是基于每行进行评估的,因为处理行需要几纳秒,这对SYSDATETIME来说很重要.但是,GETDATE具有更高的更改阈值,不受影响(或受影响较小),并且不会在每行的基础上更改 - 或需要重新评估.
你确定吗?我对这种行为的假设是否正确?
我已经搜索了这个,但除了这个之外找不到任何东西,这只涉及将SYSDATETIME()分配给变量,而不是在WHERE中使用它: SYSDATETIME()的成本是否高于GETDATE()?
此外,在示例中仅使用GETDATE: TSQL日期时间在where子句中起作用
GETDATE和之间最重要的区别SYSDATETIME是返回值的类型.SYSDATETIME不计算每一行,与每行的评估相同GETDATE.它们是运行时常量函数另请参见https://dba.stackexchange.com/questions/18459/does-sql-server-evaluate-functions-once-for-every-row
dateinquestion列的类型是什么?
使用@startdate变量时,将结果转换SYSDATETIME为date.如果不使用变量,则DATEADD示例中的结果会有不同的类型.
要使用GETDATE和SYSDATETIME等效的两个查询,您可以date显式转换为:
相比
select [....]
where dateinquestion >= CAST(DATEADD(MONTH, -2, SYSDATETIME()) AS date)
Run Code Online (Sandbox Code Playgroud)
VS
select [....]
where dateinquestion >= CAST(DATEADD(MONTH, -2, GETDATE()) as date)
Run Code Online (Sandbox Code Playgroud)
如果这两个查询的运行方式不同,我会感到惊讶.
理想情况下,您应该将它们转换为具有相同类型的类型dateinquestion.
你说那个变种用SYSDATETIME了很多CPU.如果dateinquestion有类型datetime,那么可能的解释是这个.似乎在此变体中,dateinquestion列的值datetime2(7)在比较之前被隐式转换为类型.对于每一行.首先,它使用CPU.其次,它可能会阻止优化器在此列上使用索引(如果有索引).
要查看实际情况,而不是猜测,请比较两种变体的实际执行计划.
顺便说一下,带变量的变量不等同于优化器的内联变体.优化器不知道变量的值,但它知道的价值GETDATE()和SYSDATETIME(),所以基数估计是不同的,这可能会导致不同的计划和不同的表现.