DBCC CHECKDB无法修复的损坏:索引视图包含视图定义未生成的行


14

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用于强制在上使用(仅)索引ViewNameFORCESCAN用于防止发生索引视图匹配。执行计划确认两项措施均有效。

这里没有返回任何行,这意味着两个表是相同的。(只有整数和引导列,排序规则不起作用)。

无法通过在视图上重新创建索引或通过运行来修复错误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。关于此的两个连接错误已关闭:


1
您是说在视图上删除并重新创建了索引,而DBCC CHECKDB仍然报告相同的错误?如何删除视图并从头开始创建视图?
阿龙贝特朗

来自BOL:解决索引视图上的DBCC错误 If the indexed view does not contain an aggregate over values of type float or real and you receive errors 8907 or 8708, drop the index on the view and re-create it. Do not use ALTER INDEX REBUILD to try to remove the differences between the stored and the computed view, because ALTER INDEX REBUILD does not recalculate the view before rebuilding the index. Then run DBCC CHECKTABLE on the View to verify no differences remain.
Kin Shah

@Kin我编辑了您的评论。该[1]符号在注释标记降级中不起作用。
亚伦·伯特兰

我重新创建了一切。我还让DBCC CHECKDB REPAIR_ALLOW_DATA_LOSS运行。它说它重建了视图,但是随后报告了同样的错误。
usr

您可以显示视图定义吗(如果此处太长,则显示在pastebin中)?
亚伦·伯特兰

Answers:


14

查询处理器可以为DBCC生成的(正确)查询生成无效的执行计划,以检查视图索引是否与基础视图查询生成相同的行。

查询处理器生成的计划错误地处理NULLs了该ImageObjectID列。错误地导致视图查询拒绝NULLs该列(如果不是)。考虑到NULLs排除在外,它能够匹配在过滤的Users表上的过滤后的非聚集索引ImageObjectID IS NOT NULL

通过生成使用此过滤索引的计划,可以确保不遇到带有NULLin的行ImageObjectID。这些行是从视图索引中返回的(正确),因此似乎没有损坏。

视图定义是:

SELECT
    dbo.Universities.ID AS Universities_ID, 
    dbo.Users.ImageObjectID AS Users_ImageObjectID
FROM dbo.Universities
JOIN dbo.Users
    ON dbo.Universities.AdminUserID = dbo.Users.ID

在这些列中和拒绝ON之间的子句相等性比较,但不在列中。AdminUserIDIDNULLsImageObjectID

DBCC生成的查询的一部分是:

SELECT [Universities_ID], [Users_ImageObjectID], 0 as 'SOURCE'
FROM [dbo].[mv_Universities_Users_ID] tOuter WITH (NOEXPAND) 
WHERE NOT EXISTS
( 
    SELECT 1 
    FROM   [dbo].[mv_Universities_Users_ID] tInner
    WHERE 
    (
        (
            (
                [tInner].[Universities_ID] = [tOuter].[Universities_ID]
            ) 
            OR 
            (
                [tInner].[Universities_ID] IS NULL
                AND [tOuter].[Universities_ID] IS NULL
            )
        )
        AND
        (
            (
                [tInner].[Users_ImageObjectID] = [tOuter].[Users_ImageObjectID]
            ) 
            OR 
            (
                [tInner].[Users_ImageObjectID] IS NULL 
                AND [tOuter].[Users_ImageObjectID] IS NULL
            )
        )
    )
)
OPTION (EXPAND VIEWS);

这是通用代码,以NULL感知方式比较值。这当然很冗长,但是逻辑很好。

查询处理器推理中的错误意味着可能会生成不正确使用过滤索引的查询计划,如下面的示例计划片段所示:

错误的计划

DBCC查询通过查询处理器的代码路径与用户查询不同。此代码路径包含该错误。生成使用过滤索引的计划时,它不能与USE PLAN提示一起使用,以强制该计划形状具有从用户数据库连接提交的相同查询文本。

优化程序的主要代码路径(用于用户查询)不包含此错误,因此它特定于内部查询,例如由DBCC生成的内部查询。


我可以在SQL Profiler Showplan XML事件中看到错误的计划。我将其标记为答案。为什么DBCC以不同于普通查询处理器的方式构建查询?我将向此答案的链接添加一个连接项。
usr

2
@usr DBCC可以完成用户连接无法完成的所有事情。我想它可以这样工作,因为它必须这样做,但是您必须要求像Paul Randal这样的人来获得有关此问题的真正细节。当然,他可能不会随意说。我确实知道DBCC之外有很多事情甚至做得更奇怪。有些甚至根本不通过优化器就构造执行计划!
保罗·怀特9

6

进一步的调查表明,这是DBCC CHECKDB中的错误。已打开一个Microsoft Connect错误:Unfixable DBCC CHECKDB错误(这也是一个误报,否则是奇怪的)。幸运的是,我能够产生一个副本,以便可以找到并修复该错误。

可以通过使用数据库模式来隐藏该错误。删除不相关的过滤索引或删除过滤器将隐藏该错误。有关详细信息,请参见连接项。

连接项还包含内部查询,DBCC CHECKDB使用该内部查询来验证视图内容。它没有返回任何结果,表明这是一个错误。

该错误已在某些版本中修复。我无法再在SQL Server 2014 SP2 CU 5中重现它。


重现该错误需要大量(生产)数据(这进一步证明可能是计划变更的原因)。尽管我能够删除每个表中除两列之外的所有列,但我不满意释放数据。您链接到的问题需要导致视图损坏。我重新创建了视图,因此不会由于DML导致损坏。如果查询是在DBCC CHECKDB下而不是在普通查询窗口中运行的,您是否知道可能导致不同计划的任何事情?
usr

匿名数据库刚刚上传。这是一个重建所有索引并重新创建视图的脚本:pastebin.com/jPEALeEw(用于重置所有内容并确保物理结构正常)。其他有用的脚本:pastebin.com/KxNSwm2J该脚本应仅运行,问题应立即修复。
usr

.bak的镜像:mega.co.nz/…–
usr

在11.0.3349中使用-T272,4199,3604。已启用4199的查询处理器修复程序。我只是删除了那个TF。也许我们需要制定正确的查询计划。我现在已经设置了1GB RAM并重新启动了实例(原为8GB)。这改变了我在NLJ看到的两个合并联接之一。仍在复制。要尝试一些计划变化,我添加和删除了以下行:pastebin.com/y972Sx4d如果我在查询的“左反半联接”部分中遇到了合并联接或哈希,该错误似乎会触发。尝试以下操作:向用户添加100k行。这确实为我提供了(并行)哈希联接。
usr

我刚刚将“ plans.zip”上传到了连接项,其中包含用于DBCC CHECKDB查询的不同执行计划。在大学中,由于行数不同,我至少可以制定三个不同的计划。只有使用循环联接计划,才不会发生此问题。使用合并和哈希联接,该错误是可重现的。
usr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.