;WITH
cte_Date ( DateCode_FK ) AS (
SELECT DATEADD( DAY,
1 - ROW_NUMBER() OVER (
ORDER BY so1.object_id ),
GETDATE() )
FROM sys.objects so1
CROSS APPLY sys.objects so2 )
SELECT TOP 10 d.DateCode_FK
FROM cte_Date d
ORDER BY d.DateCode_FK DESC;
Run Code Online (Sandbox Code Playgroud)
没什么特别有趣的查询,但是如果我使用以下ORDER BY子句运行它,我会收到一条错误消息:
Msg 517, Level 16, State 1, Line 4
向“日期时间”列添加值会导致溢出。
但是,没有ORDER BY子句,它运行得很好。此外,如果我在同一服务器上的同一实例中包含的其他目录上运行查询,无论是否使用该ORDER BY子句,该查询都可以正常运行。
我查看了受影响的目录和查询按预期运行的目录之间的配置选项和兼容性级别,但没有发现任何可能保证差异的内容。有没有其他人遇到过类似的问题?我现在可以解决它,但理想情况下需要能够解决问题,无论它是什么。
潜在提示 - 如果您在目录中有相对大量的对象(> 5000),您 - 可能 - 能够重现该错误......这发生在我最大的目录中,如果我在其中包含一个 TOP CTE,ORDER BY 问题消失了。
SQL Server 不保证标量表达式的计算时间或计算次数。这意味着,查询可能会引发错误取决于操作的顺序在执行计划中可能(也可能不会)在运行时这样做。
脚本使用CROSS APPLY,其中CROSS JOIN,可能是为了,但问题是,在该行的潜在数量ROW_NUMBER的计算依赖于规模sys.objects的交叉产品。
对于具有足够对象的数据库,DATEADD结果溢出是预期的风险。例如,这可以使用AdventureWorks示例数据库重现,该数据库在sys.objects. 叉积的大小为637 * 637 = 405,769;以下会引发溢出错误:
SELECT DATEADD(DAY, 1 - 405769, GETDATE());
Run Code Online (Sandbox Code Playgroud)
有人可能会争辩说,没有必要为未返回的行(因此不会抛出错误)实现表达式的结果,但这不是今天的工作方式。
考虑:
ROW_NUMBER将给予最低值DateCode_FK的DATEADD(DAY, 1 - ROW_NUMBER()...表达ORDER BY是DateCode_FK DESC如果优化器包含逻辑来推理较低的行数会导致较高的 DateCode_FK值,则不需要显式排序。只有十行需要流经执行计划。十个最低的行号保证产生十个最高DateCode_FK值。
无论如何,即使存在 Sort,论据是 SQL Server 不应该抛出错误,因为实际返回的十行中没有一个与溢出错误相关联。正如我上面所说,“这不是今天的工作方式”。
避免错误的替代公式(尽管仍然不能保证这样做 - 请参阅我的开场白),使行编号具有确定性,并使用CROSS JOIN:
WITH cte_Date (DateCode_FK) AS
(
SELECT TOP (10)
DATEADD
(
DAY,
1 - ROW_NUMBER() OVER (
ORDER BY
so1.[object_id],
so2.[object_id]),
GETDATE()
)
FROM sys.objects AS so1
CROSS JOIN sys.objects AS so2
ORDER BY
ROW_NUMBER() OVER (
ORDER BY
so1.[object_id],
so2.[object_id]) ASC
)
SELECT TOP (10) -- Redundant TOP
d.DateCode_FK
FROM cte_Date AS d
ORDER BY
d.DateCode_FK DESC;
Run Code Online (Sandbox Code Playgroud)