usr*_*usr 16 sql-server sql-server-2014 computed-column
我正在跟进有关计算列中奇怪值的问题PERSISTED
。那里的答案对这种行为是如何产生的做出了一些猜测。
我在问以下问题:这不是一个彻头彻尾的错误吗?被PERSISTED
列曾经允许这样的行为?
DECLARE @test TABLE (
Col1 INT,
Contains2 AS CASE WHEN 2 IN (Col1) THEN 1 ELSE 0 END PERSISTED) --depends on Col1
INSERT INTO @test (Col1) VALUES
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5))
SELECT * FROM @test --shows impossible data
UPDATE @test SET Col1 = Col1*1 --"fix" the data by rewriting it
SELECT * FROM @test --observe fixed data
/*
Col1 Contains2
2 0
2 0
0 1
4 0
3 0
Col1 Contains2
2 1
2 1
0 0
4 0
3 0
*/
Run Code Online (Sandbox Code Playgroud)
请注意,数据看起来“不可能”,因为计算列的值与其定义不对应。
众所周知,查询中的非确定性函数可能表现得很奇怪,但这似乎违反了持久计算列的约定,因此应该是非法的。
插入随机数可能是一个人为的场景,但如果我们插入NEWID()
值或SYSUTCDATETIME()
? 我认为这是一个可能实际表现出来的相关问题。
这当然是一个错误。这些col1
值恰好是涉及随机数的表达式的结果这一事实显然不会改变正确值col2
应该是什么。DBCC CHECKDB
如果这是针对永久表运行的,则返回错误。
create table test (
Col1 INT,
Contains2 AS CASE WHEN 2 IN (Col1) THEN 1 ELSE 0 END PERSISTED);
INSERT INTO test (Col1) VALUES
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5)),
(ABS(CHECKSUM(NEWID()) % 5));
DBCC CHECKDB
Run Code Online (Sandbox Code Playgroud)
给出(对于我的测试运行,其中有一个“不可能”的行)
Msg 2537, Level 16, State 106, Line 17
Table error: object ID 437576597, index ID 0, partition ID 72057594041008128, alloc unit ID 72057594046251008 (type In-row data), page (1:121), row 0. The record check (valid computed column) failed. The values are 2 and 0.
DBCC results for 'test'.
There are 5 rows in 1 pages for object "test".
CHECKDB found 0 allocation errors and 1 consistency errors in table 'test' (object ID 437576597).
Run Code Online (Sandbox Code Playgroud)
它还报告说
repair_allow_data_loss 是 DBCC CHECKDB 发现的错误的最低修复级别
如果采用修复选项,则会毫不客气地删除整行,因为它无法判断哪一列已损坏。
附加调试器显示NEWID()
每个插入的行正在评估两次。一次在CASE
表达式被计算之前,一次在它内部。
一种可能的解决方法可能是使用
INSERT INTO @test
(Col1)
SELECT ( ABS(CHECKSUM(NEWID()) % 5) )
FROM (VALUES (1),(1),(1),(1),(1)) V(X);
Run Code Online (Sandbox Code Playgroud)
出于某种原因,这避免了这个问题,并且每行只计算一次表达式。
归档时间: |
|
查看次数: |
520 次 |
最近记录: |