更新行为

时间:2013-01-29 07:35:55

标签: sql sql-server tsql

当我在更新查询文本中出错时,我发现了不可预知的查询结果。这是更新的查询文本。

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)。 执行计划如下:

在这种错误的情况下,这种情况是否会相同?

如果是,这个行为有什么实际价值吗?

1 个答案:

答案 0 :(得分:2)

对于各种错误,情况都不一样。您有一个非确定性更新语句,也就是说理论上,子查询RNT的任何值都可以应用于@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);

online manual州:

  

如果语句,则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的新问题。