Sql-Server

DBCC CHECKDB 無法修復的損壞:索引視圖包含視圖定義未生成的行

  • May 23, 2017

**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用於防止發生索引視圖匹配。執行計劃確認這兩種措施都有效。

這裡沒有返回任何行,這意味著這兩個表是相同的。(只有整數和 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. 關於此的兩個連接錯誤已關閉:

查詢處理器可以為 DBCC 生成的(正確)查詢生成無效的執行計劃,以檢查視圖索引是否生成與基礎視圖查詢相同的行。

查詢處理器生成的計劃不正確地處理NULLsImageObjectID列。它錯誤地認為視圖查詢拒絕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相等比較AdminUserIDID拒絕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 生成的內部查詢。

引用自:https://dba.stackexchange.com/questions/47295