我们有一个包含列的 OrderLines 表:
Quantity int not null
QtyCancelled int not null
QtyBackorder int not null
QtyPicking int not null
QtyPacking int not null
QtyShiped int not null
计算列和持久列 FulfillmentStatusId 为:
dbo.clr_GetFulfillmentStatusByLineQuantities(Quantity, QtyCancelled, QtyBackorder, QtyPicking, QtyPacking, QtyShiped)
“clr_GetFulfillmentStatusByLineQuantities”,当然,通过标量函数映射到数据库中的 ASSEMBLY,相关方法 (C#) 标记为:
[SqlFunction(DataAccess = None, IsDeterministic = true, IsPrecise = true, SystemDataAccess = None)]
关于这个问题,我多次针对这个表运行 DBCC CHECKTABLE ,它仍然是 has_unchecked_assembly_data=1。当列首次添加到表中时确实如此,但我相信 DBCC CHECKTABLE 命令在迁移到 SQL 2016 之前成功了。
虽然该表已在 has_unchecked_assembly_data=1 下使用了很长时间,但似乎对该表的功能没有影响。我担心 ALTER ASSEMBLY 在不使用 WITH UNCHECKED DATA 时抛出异常,然后在我确实使用该选项时抛出另一个异常,但似乎“根据 MVID”更新程序集。
对不起,如果我漫无边际,我不会问太多问题而且我主要是潜伏。
不过,请提前致谢!
更新 (20180917T17:34-05:00):感谢 Sean 提出了初步方向。DBCC CHECKTABLE ('OrderLines') WITH EXTENDED_LOGICAL_CHECKS的结果是两行类似于:
Msg 2537, Level 16, State 106, Line 1
Table error: object ID 1486732449, index ID 1, partition ID 72057594403946496, alloc unit ID 72057594422755328 (type In-row data), page (1:1430554), row 5. The record check (valid computed column) failed. The values are 38 and 0.
因此,我对表的主键(即上面指示的索引 ID 1)执行了 REBUILD,这成功了。然而,重新运行DBCC CHECKTABLE('OrderLines') WITH EXTENDED_LOGICAL_CHECKS再次返回类似的错误,只是这次使用不同的分区 ID 和分配单元 ID(正如人们所预料的那样)。
极端的解决方案可能是删除、重新创建并使用标识插入重新填充表,可以这么说,“从轨道上删除站点”,但出于显而易见的原因,这是极端的。
“表的聚集索引中的计算列数据似乎不一致”的正确解决方案是什么?
OP在这里,回答我自己的(也是第一个)问题!
在肖恩·加拉迪 (Sean Gallardy) 的帮助下,使用
EXTENDED_LOGICAL_CHECKS
指出了与持久计算列的数据不一致的地方。我首先尝试重新创建主键(聚集索引),但这实际上并没有解决任何问题(一个极端而奇怪的解决方案)。我也尝试使用
DBCC CHECKTABLE ('{table}', REPAIR_ALLOW_DATA_LOSS)
,但再次返回相同的错误。我不相信任何东西都被修复了。我的第一个解决方案是删除并重新创建持久计算列。这奏效了。
但是,考虑到这也有点“极端”(考虑到该表有 1000 万多行,并且因为还有一个针对该列的索引而需要永远这样做),我对更直接的解决方案感到好奇。
因为只有两行报告了
DBCC CHECKTABLE
它们的页面和行引用,所以我调查了DBCC PAGE
。精确地使用这个命令得到了实际的行数据/行标识,当我执行驱动计算列的 CLR 方法时,确实存在不一致。基本实际和不一致的表格数据:
FulfillId
在这种情况下应该是 1(表示已取消),但是这两个表行表示两行都是 0(未完成/未完成)。我使用
SELECT
语句通过 CLR 函数运行实际行数据:这基本上返回了完全相同的信息,
ComputedFulfillId
也解析为 0(打开)。因此,我直接在 .Net 控制台应用程序中重新测试了 CLR 代码,并给出了应该在 SQL 调用中传递的显式值,结果是预期值 1(已取消)。我修改了
SELECT
语句以包括使用显式常量值而不是来自可疑行的值对 CLR 方法的调用:该
ForcedFulfillId
列包含正确的值 1。使用 DBCC PAGE 查找确切的行标识并更新有问题的行会强制重新计算计算列数据。一个决赛
DBCC CHECKTABLE
没有返回任何错误,一切都很好。因此,与其删除并重新创建整个计算列,不如使用
DBCC PAGE
来自的信息DBCC CHECKTABLE({table}) WITH EXTENDED_LOGICAL_CHECKS
来修复导致错误的原始“has_unchecked_assembly_data=1”问题ALTER ASSEMBLY
。呼
抱歉冗长的解释 - 想确保我为下一个可怜的灵魂记录了我的旅行。