TL;DR:我在索引视图中有无法修复的损坏。以下是详细信息:
跑步
DBCC CHECKDB([DbName]) WITH EXTENDED_LOGICAL_CHECKS, DATA_PURITY, NO_INFOMSGS, ALL_ERRORMSGS
在我的一个数据库上产生以下错误:
消息 8907,级别 16,状态 1,第 1 行空间索引、XML 索引或索引视图“ViewName”(对象 ID 784109934)包含视图定义未生成的行。这不一定表示此数据库中的数据存在完整性问题。(...)
CHECKDB 在表“ViewName”中发现 0 个分配错误和 1 个一致性错误。
repair_rebuild 是最低修复级别 (...)。
我确实理解此消息表明索引视图“ViewName”的物化数据与基础查询产生的数据不同。但是,手动验证数据不会出现任何差异:
SELECT * FROM ViewName WITH (NOEXPAND)
EXCEPT
SELECT ...
from T1 WITH (FORCESCAN)
join T2 on ...
SELECT ...
from T1 WITH (FORCESCAN)
join T2 on ...
EXCEPT
SELECT * FROM ViewName WITH (NOEXPAND)
NOEXPAND
用于强制使用 . 上的(唯一)索引ViewName
。FORCESCAN
用于防止发生索引视图匹配。执行计划确认这两种措施都有效。
这里没有返回任何行,这意味着这两个表是相同的。(只有整数和 guid 列,排序规则不起作用)。
无法通过在视图上重新创建索引或运行来修复错误DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS
。重复修复也无济于事。为什么会DBCC CHECKDB
报这个错误?如何摆脱它?
(即使重建修复了它,我的问题仍然存在 - 尽管我的数据检查查询运行成功,为什么会报告错误?)
更新:该错误已在某些版本中得到修复。我无法再在 SQL Server 2014 SP2 CU 5 中重现它。2014 SP2 KB包含一个没有 KB 文章的修复:Creating non-clustered index causes DBCC CheckDB With Extended_Logical_Checks to raise corruption error
. 关于此的两个连接错误已关闭:
- https://connect.microsoft.com/SQLServer/feedback/details/847233/creating-non-clustered-index-causes-dbcc-checkdb-with-extended-logical-checks-to-raise-corruption-error
- https://connect.microsoft.com/SQLServer/feedback/details/795478/unfixable-dbcc-checkdb-error-that-is-also-a-false-positive-and-otherwise-strange
查询处理器可以为 DBCC 生成的(正确)查询生成无效的执行计划,以检查视图索引是否生成与基础视图查询相同的行。
查询处理器生成的计划不正确地处理
NULLs
该ImageObjectID
列。它错误地认为视图查询拒绝NULLs
该列,而实际上它没有。考虑到NULLs
被排除在外,它能够匹配过滤的Users
表上的过滤非聚集索引ImageObjectID IS NOT NULL
。通过生成使用此过滤索引的计划,它确保不会遇到带有
NULL
in的行。ImageObjectID
这些行是从视图索引(正确地)返回的,因此在没有损坏时似乎存在损坏。视图定义为:
子句之间的
ON
相等比较AdminUserID
和ID
拒绝NULLs
在这些列中,但不是从ImageObjectID
列中。DBCC 生成的查询的一部分是:
这是以
NULL
感知方式比较值的通用代码。这当然很冗长,但逻辑很好。查询处理器推理中的错误意味着可能会生成错误使用过滤索引的查询计划,如下面的示例计划片段所示:
DBCC 查询通过查询处理器采用与用户查询不同的代码路径。此代码路径包含错误。生成使用过滤索引的计划时,它不能与
USE PLAN
提示一起使用以强制该计划形状与从用户数据库连接提交的相同查询文本。主要优化器代码路径(用于用户查询)不包含此错误,因此它特定于 DBCC 生成的内部查询。
进一步调查表明这是 DBCC CHECKDB 中的一个错误。已打开 Microsoft Connect 错误:无法修复的 DBCC CHECKDB 错误(这也是误报,否则很奇怪)。幸运的是,我能够生成一个重现,以便可以找到并修复错误。
可以通过使用数据库模式来隐藏错误。删除不相关的过滤索引或删除过滤器会隐藏错误。有关详细信息,请参阅连接项。
连接项还包含 DBCC CHECKDB 用来验证视图内容的内部查询。它没有返回任何结果,表明这是一个错误。
该错误已在某些版本中得到修复。我无法再在 SQL Server 2014 SP2 CU 5 中重现它。