DBCC CHECKDB 無法修復的損壞:索引視圖包含視圖定義未生成的行
**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
這些行是從視圖索引(正確地)返回的,因此在沒有損壞時似乎存在損壞。視圖定義為:
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
相等比較AdminUserID
和ID
拒絕NULLs
在這些列中,但不是從ImageObjectID
列中。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 生成的內部查詢。