Sql-Server

SQL Server,我無法修復的一致性錯誤

  • December 14, 2021

使用者數據庫上的 DBCC CHECKDB 返回此錯誤

Msg 8992, Level 16, State 1, Line 1
Check Catalog Msg 3851, State 1: An invalid row (class=128,depid=65536,depsubid=0) was found in the system table sys.syssingleobjrefs (class=128).

此錯誤在使用者數據庫中,而不是在master!當人們嘗試檢查主數據庫並在不同的伺服器上恢復時,Internet 上到處都是專門針對此錯誤的文章。事實並非如此。

我嘗試了所有常用的魔法,但沒有成功。

DBCC CHECKDB WITH ALL_ERRORMSGS, NO_INFOMSGS
--error

ALTER DATABASE DBCopy SET SINGLE_USER WITH ROLLBACK IMMEDIATE

DBCC CHECKDB (DBCopy, REPAIR_ALLOW_DATA_LOSS) 
--output reports the same error

DBCC CHECKDB WITH ALL_ERRORMSGS, NO_INFOMSGS
--error

--no hope but just in case
ALTER DATABASE DBCopy SET EMERGENCY

DBCC CHECKDB (DBCopy, REPAIR_ALLOW_DATA_LOSS) 
--the same error reported

DBCC CHECKDB WITH ALL_ERRORMSGS, NO_INFOMSGS
--error

ALTER DATABASE DBCopy SET MULTI_USER

我們沒有沒有此錯誤的備份。這個錯誤看起來完全無害。數據庫和應用程序工作得很好。

微軟 SQL Server 2019 (RTM-CU14)

數據庫已啟用記憶體。

在我開始重建數據庫之前有什麼要嘗試的嗎?

PS我重建數據庫。

看來您有一行sys.syssingleobjrefs與其他系統表中的行不對應。

sys.syssingleobjrefs被列為System Base Table,並且只能通過 DAC(管理員)連接訪問。您可以使用sqlcmd.exe -A.

文件說:

若要綁定到系統基表,使用者必須使用專用管理員連接 (DAC) 連接到 SQL Server 實例。嘗試從系統基表執行 SELECT 查詢而不使用 DAC 進行連接會引發錯誤。

重要的

使用 DAC 訪問系統基表僅適用於 Microsoft 人員,它不是受支持的客戶方案。

只有在沒有其他選擇的情況下,我才會建議這樣做。亂用系統表會破壞您的數據庫。

因此,您以管理員身份登錄或以sa. 您可能只想刪除無效行,希望這可以解決問題。

警告!:

這樣做完全由您自擔風險。我強烈建議您備份數據庫,將其還原到完全不同的實例,然後先在那裡進行測試。

USE [DBCopy];
GO

ALTER DATABASE DBCopy SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO

DELETE FROM sys.syssingleobjrefs
WHERE class = 128
 AND depid = 65536
 AND depsubid = 0;

GO

DBCC CHECKDB (DBCopy, REPAIR_ALLOW_DATA_LOSS)
 WITH NO_INFOMSGS, TABLOCK;

GO

修復或刪除損壞的行將不起作用,因為此系統表不可通過經典 T-SQL 寫入。

根據該使用者數據庫的大小,可以轉儲/恢復數據庫以重建系統目錄,從而消除對象和目錄之間的不同步。

我建議您不要備份/恢復而是轉儲/恢復,因為備份/恢復將保持對象和目錄之間的不同步。

首先,確保數據庫上方的應用程序已關閉,或者至少與數據庫的連接池已關閉。

您可以首先將數據庫設置為單使用者模式(如果未關閉,這將意味著應用程序停機)。

ALTER DATABASE DBCopy SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

然後通過 SSMS 使用右鍵點擊相關數據庫並選擇“任務 > 生成腳本…”

在以下嚮導中,選擇要導出的對象(系統表引用的對象)。

導出完成後,刪除系統表引用的對象並通過執行導出的腳本恢復它們。

然後將數據庫返回到 MULTI_USER :

ALTER DATABASE DBCopy SET MULTI_USER;

我建議您首先通過預生產或基準環境嘗試該過程。這樣,您將能夠在完全不影響生產的情況下測試解決方案。

PS:要找出您的系統表涉及哪個對象,您將不得不探勘 syssingleobjrefs 系統表(正如@Charlieface 所說,sqlcmd -A哪個是通過 DAC 的管理員訪問權限)。

如果您沒有在伺服器上安裝 sqlcmd,您可能必須啟用“遠端 DAC”才能通過網路使用管理員訪問權限。

PS (2) :最棘手的部分可能是找出哪個對象與您的損壞數據相關,因為這些是系統表和未記錄的表,很難告訴您該引用背後依賴於哪個對象。

PS(3):如果您無法將手指放在該系統表引用的對像上。最後一個選項是轉儲/恢復表的所有對象(這當然會涉及更長的停機時間)。

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