JW-*_*-OP 6 sql-server sql-clr computed-column dbcc-checktable
我们有一个带有列的 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
Run Code Online (Sandbox Code Playgroud)
计算和持久化列 FulfillmentStatusId 为:
dbo.clr_GetFulfillmentStatusByLineQuantities(Quantity, QtyCancelled, QtyBackorder, QtyPicking, QtyPacking, QtyShiped)
Run Code Online (Sandbox Code Playgroud)
“clr_GetFulfillmentStatusByLineQuantities”,当然,通过标量函数映射到数据库中的 ASSEMBLY,关联方法 (C#) 标记为:
[SqlFunction(DataAccess = None, IsDeterministic = true, IsPrecise = true, SystemDataAccess = None)]
Run Code Online (Sandbox Code Playgroud)
参考这个问题,我已经多次针对这个表运行 DBCC CHECKTABLE ,它仍然保持为 has_unchecked_assembly_data=1。首次将列添加到表中时确实如此,但我相信 DBCC CHECKTABLE 命令在迁移到 SQL 2016 之前已成功。
尽管该表已使用很长时间且 has_unchecked_assembly_data=1,但似乎对该表的功能没有影响。我很关心ALTER ASSEMBLY不使用时取消选中数据时,则抛出抛出异常的另一个异常,当我没使用该选项,但出现的装配反正“根据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.
Run Code Online (Sandbox Code Playgroud)
所以我对表的主键(即上面指示的索引ID 1)执行了REBUILD,成功了。但是,重新运行DBCC CHECKTABLE('OrderLines') WITH EXTENDED_LOGICAL_CHECKS再次返回了类似的错误,只是这次使用了不同的分区 ID 和分配单元 ID(正如人们所期望的)。
极端的解决方案可能是使用身份插入删除、重新创建和重新填充表,可以这么说,“从轨道核对站点”,但出于显而易见的原因,这是极端的。
“表的聚集索引中似乎存在不一致的计算列数据”的正确解决方案是什么?
在这里,回答我自己的(也是第一个)问题!
在 Sean Gallardy 的帮助下, usingEXTENDED_LOGICAL_CHECKS
指出与持久计算列的数据不一致。我首先尝试重新创建主键(聚集索引),但这实际上并没有解决任何问题(一个极端而奇怪的解决方案)。
我也尝试使用DBCC CHECKTABLE ('{table}', REPAIR_ALLOW_DATA_LOSS)
,但再次返回相同的错误。我不相信任何东西都被修复了。
我的第一个解决方案是删除并重新创建持久化的计算列。这奏效了。
但是,认为这也有点“极端”(考虑到该表有 1000 万行以上,并且需要永远执行此操作,因为该列还有一个索引),我对更直接的解决方案感到好奇。
由于当时只有两行报告DBCC CHECKTABLE
与他们的页面和行引用我看着DBCC PAGE
。精确地使用此命令为我提供了实际的行数据/行标识,当我执行驱动计算列的 CLR 方法时,确实存在不一致。
基本的实际和不一致的表数据:
OrderLineId QtyOrd QtyCancl QtyBack QtyPick QtyPack QtyShip FulfillId
1234567 4 12 0 0 0 0 0
4567890 4 12 0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)
FulfillId
在这种情况下应为 1(表示已取消),但这两个表行表示两行均为 0(未完成/未完成)。
我使用以下SELECT
语句通过 CLR 函数运行了实际的行数据:
select
ol.OrderLineId,
ol.QtyOrd, ol.QtyCancl, ol.QtyBack, ol.QtyPick, ol.QtyPack, ol.QtyShip,
ol.FulfillId [CurrentFulfillId],
CLR(ol.QtyOrd, ol.QtyCancl, ol.QtyBack, ol.QtyPick, ol.QtyPack, ol.QtyShip) [ComputedFulfillId],
from
OrderLines [ol]
where
ol.OrderLineId in (1234567, 4567890)
Run Code Online (Sandbox Code Playgroud)
这基本上返回了完全相同的信息,ComputedFulfillId
也解析为 0(打开)。所以我直接在 .Net 控制台应用程序中重新测试了 CLR 代码,并给出了应该在 SQL 调用中传递的显式值,结果是预期值 1(取消)。
我修改了SELECT
语句以包含使用显式常量值而不是来自可疑行的值对 CLR 方法的调用:
SELECT ..., CLR(4, 12, 0, 0, 0, 0) [ForcedFulfillId] FROM OrderLines [ol] ...
Run Code Online (Sandbox Code Playgroud)
并且该ForcedFulfillId
列包含正确的值 1。
使用 DBCC PAGE 查找确切的行标识并更新有问题的行会强制重新计算计算列数据。一场决赛DBCC CHECKTABLE
没有返回任何错误,一切又好起来了。
因此,与其删除并重新创建整个计算列,不如使用DBCC PAGE
来自DBCC CHECKTABLE({table}) WITH EXTENDED_LOGICAL_CHECKS
允许我修复导致ALTER ASSEMBLY
错误的原始“has_unchecked_assembly_data=1”问题的信息。
哇
抱歉,冗长的解释 - 想确保我为下一个可怜的灵魂记录了我的旅行。
归档时间: |
|
查看次数: |
154 次 |
最近记录: |