当我尝试运行查询时
SELECT
App.AppName,
DATEDIFF(second, DISPDATE, RTSDATE) AS IncidentLengthSeconds
--,[FDMTEST].[dbo].[IncApp].*
FROM
FDMTEST.[dbo].[IncApp]
JOIN
FDMTEST.dbo.Inc ON IncApp.IncId = Inc.Id
JOIN
FDMTEST.dbo.App AS App ON IncApp.AppId = App.Id
WHERE
RTSDATE > REDEPDATE
AND AppName IN ('E1', 'E2', 'E3', 'E4')
AND inc.incdate >= '2012-01-01 00:00:00'
AND inc.incdate <= '2012-12-31 00:00:00'
我收到错误
Msg 535,Level 16,State 0,Line 1
日期函数导致溢出。分隔两个日期/时间实例的日期部分数量太大。尝试使用具有不太精确的日期部分的datediff。
显而易见的答案是,DATEDIFF(第二,DISPDATE,RTSDATE)的某些结果很大,但分钟中最大的差距为331分钟。
现在真正有趣的部分。如果我取消注释“,[FDMTEST]。[dbo]。[IncApp]。*”查询不再崩溃。我认为MS-SQL服务器正在进行某种内部优化会导致问题。
提到的所有表都是普通表而不是视图。
Microsoft SQL Server 2012(SP1) - 11.0.3128.0(X64)
上的标准版(64位)
版权所有(c)Microsoft Corporation
Windows NT 6.2(Build 9200:)(管理程序)
编辑: 我找到了incdate = 1993-10-29 12:55:00.000和DISPDATE ='1800-01-01 00:00:00.000'的记录
此记录是使用WHERE子句过滤掉的,但SQL服务器是否可能正在计算DATEDIFF?
计划:
|--Hash Match(Inner Join, HASH:([FDMTEST].[dbo].[IncApp].[IncId])=([FDMTEST].[dbo].[Inc].[Id]))
|--Hash Match(Inner Join, HASH:([App].[Id])=([FDMTEST].[dbo].[IncApp].[AppId]))
| |--Index Seek(OBJECT:([FDMTEST].[dbo].[App].[UQ_App] AS [App]), SEEK:([App].[AppName]='E1' OR [App].[AppName]='E2' OR [App].[AppName]='E3' OR [App].[AppName]='E4') ORDERED FORWARD)
| |--Compute Scalar(DEFINE:([Expr1008]=datediff(second,[FDMTEST].[dbo].[IncApp].[DISPDATE],[FDMTEST].[dbo].[IncApp].[RTSDATE])))
| |--Clustered Index Scan(OBJECT:([FDMTEST].[dbo].[IncApp].[PK__IncApp__4ED38FEE]), WHERE:([FDMTEST].[dbo].[IncApp].[RTSDATE]>[FDMTEST].[dbo].[IncApp].[REDEPDATE]))
|--Index Seek(OBJECT:([FDMTEST].[dbo].[Inc].[INC_EventIndex1]), SEEK:([FDMTEST].[dbo].[Inc].[INCDATE] >= '2012-01-01 00:00:00.000' AND [FDMTEST].[dbo].[Inc].[INCDATE] <= '2012-12-31 00:00:00.000') ORDERED FORWARD)
评论未提交(工作版):
|--Hash Match(Inner Join, HASH:([App].[Id])=([FDMTEST].[dbo].[IncApp].[AppId]))
|--Index Seek(OBJECT:([FDMTEST].[dbo].[App].[UQ_App] AS [App]), SEEK:([App].[AppName]='E1' OR [App].[AppName]='E2' OR [App].[AppName]='E3' OR [App].[AppName]='E4') ORDERED FORWARD)
|--Hash Match(Inner Join, HASH:([FDMTEST].[dbo].[Inc].[Id])=([FDMTEST].[dbo].[IncApp].[IncId]))
|--Index Seek(OBJECT:([FDMTEST].[dbo].[Inc].[INC_EventIndex1]), SEEK:([FDMTEST].[dbo].[Inc].[INCDATE] >= '2012-01-01 00:00:00.000' AND [FDMTEST].[dbo].[Inc].[INCDATE] <= '2012-12-31 00:00:00.000') ORDERED FORWARD)
|--Compute Scalar(DEFINE:([Expr1008]=datediff(second,[FDMTEST].[dbo].[IncApp].[DISPDATE],[FDMTEST].[dbo].[IncApp].[RTSDATE])))
|--Clustered Index Scan(OBJECT:([FDMTEST].[dbo].[IncApp].[PK__IncApp__4ED38FEE]), WHERE:([FDMTEST].[dbo].[IncApp].[RTSDATE]>[FDMTEST].[dbo].[IncApp].[REDEPDATE]))
从我可以看到它在一个案例中计算过滤器之前的标量而在另一个案例中没有计算。有没有办法尽早强制执行?
答案 0 :(得分:1)
你可能最好在你的SELECT
子句中编写表达式,这样它总会产生一个没有溢出的结果。正如您所发现的那样,优化器可以评估您SELECT
的表达式,即使是最终会被WHERE
子句过滤掉的记录,但是无论执行计划如何,这样的事情都应该有效:
case
when datediff(year, DISPDATE, RTSDATE) < 50
then datediff(second, DISPDATE, RTSDATE)
else
null
end as [IncidentLengthSeconds]
它不漂亮,但应该有效。也许其他人知道更简洁的建筑?
答案 1 :(得分:0)
我的解决方法是将其添加到where子句
AND
(
(RTSDATE > REDEPDATE AND DATEDIFF(YEAR, DISPDATE, RTSDATE) < 2)
OR
RTSDATE <= REDEPDATE
)
这似乎解决了这个问题,但我担心该计划可能会在DATEDIFF SECOND之后再次尝试执行此操作。
原始查询适用于2个月的备份。