当我在更新查询文本中出错时,我发现了不可预知的查询结果。这是更新的查询文本。
DECLARE @T TABLE (Id int,[Name] nvarchar(100),RNA int)
INSERT INTO @T(Id,[Name])
SELECT [Id],[Name]
FROM (VALUES (1,N'D'),
(2,N'B'),
(3,N'S'),
(4,N'A'),
(5,N'F')
) AS vtable([Id],[Name])
UPDATE @T
SET RNA = T.RN
FROM (
select PP.Name,ROW_NUMBER() OVER(ORDER BY PP.Name) RN,PP.RNA from @T PP
) T
select * from @T
我知道错误在哪里:
UPDATE @T
应该是
UPDATE T
但为什么结果(带有“坏”查询)看起来像:
Id Name RNA
---- ----- -------
1 D 1
2 B 5
3 S 1
4 A 5
5 F 1
我怀疑1和5的值是MIN(Id)和MAX(Id)。 执行计划如下:
在这种错误的情况下,这种情况是否会相同?
如果是,这个行为有什么实际价值吗?
答案 0 :(得分:2)
对于各种错误,情况都不一样。您有一个非确定性更新语句,也就是说理论上,子查询RN
中T
的任何值都可以应用于@T
中的任何值。您基本上正在运行此UPDATE
版本:
SELECT *
FROM @t a
CROSS JOIN
( SELECT TOP 1
PP.Name,
ROW_NUMBER() OVER(ORDER BY PP.Name) RN,
PP.RNA
FROM @T PP
ORDER BY NEWID()
) T
OPTION (FORCE ORDER);
如果语句,则UPDATE语句的结果是未定义的 包含一个FROM子句,它没有以这种方式指定 一个值可用于更新的每个列事件, 即如果UPDATE语句不确定。
有趣的是,如果你运行上面的命令,每次都会得到不同的结果(除非连续两次获得相同结果的概率为1/25),如果你使用{{1删除随机排序对于每一行,您将获得相同的NEWID()
值,但更新始终返回相同的结果,并且有两个不同的RN
s。我并不感到惊讶,结果与没有随机排序保持一致,因为没有对数据进行任何更改,并且没有引入随机因素,我希望优化器能够提出相同的执行计划,无论它运行多少次。
由于在更新查询中未指定显式排序,因此顺序是由叶子上记录的顺序决定的,如果更改了记录的顺序,则结果会更改。这可以通过将RN
的记录插入具有不同ID的新表
@T
我看不出为什么这总是DECLARE @T2 TABLE (Id int,[Name] nvarchar(100),RNA int);
INSERT @T2
SELECT id, Name, NULL
FROM @T
ORDER BY ROW_NUMBER() OVER(ORDER BY NEWID())
OPTION (FORCE ORDER);
UPDATE @T2
SET RNA = T.RN
FROM (
select PP.Name,ROW_NUMBER() OVER(ORDER BY PP.Name) RN,PP.RNA from @T2 PP
) T
SELECT *
FROM @T2;
的最小值或最大值,但我希望你必须深入研究优化器才能找到它。这可能是一个更适合the dba stack exchange的新问题。