Sql-Server

檢測和修復 SQL Server 鏡像數據庫上的數據庫損壞

  • December 10, 2020

我是我現在的公司的新手,我們有系統管理員,但沒有 DBA。過去,我曾在其他公司處理過與 DBA 相關的問題。我已經在其他數據庫(Foxpro 和 Access)中遇到並糾正了數據庫損壞,並且至少能夠記錄損壞的數據,以便可以重新輸入。我從未遇到或懷疑 SQL Server 數據庫損壞。我懷疑我在使用正在鏡像的 SQL Server 2005 數據庫時遇到了這種情況。

情況是傳遞給數據庫的簡單刪除命令不會刪除某些表中的數據。我真的必須通過 SQL Server Management Studio 進入並發出刪除命令來清除這些表。臨時表中有 144,000 到 32,000,000 條記錄,這些數據佔數據庫的 90% 以上(在刪除記錄和縮小數據庫後確定)。完成此清理後,傳遞到測試伺服器上的數據庫的刪除命令就可以工作了。

我的第一道攻擊線是針對數據庫副本執行 DBCC CHECKDB。我對備份執行它,沒有發現損壞。我們無法獲得數據庫的精確副本,因為我的系統管理員過去曾遇到過問題,即數據庫伺服器需要長達 6 小時才能上線,並且他不想同時禁用實時 SQL 伺服器和鏡像 SQL 伺服器。

我的第一個問題是我是否應該信任數據庫備份以包含 DBCC CHECKDB 會發現的損壞數據。如果備份不儲存損壞,最好的方法是停止然後恢復活動數據庫和鏡像數據庫以獲取 LDF 和 MDF 文件的副本?

最後,如果我在測試中發現損壞,我將如何確定可能顯示損壞的頁面內容?

您所看到的不太可能是腐敗。

此問題的更可能原因是“應用程序”未DELETE FROM正確發出命令,或者以您認為的方式發出命令。可能由於某種原因正在回滾DELETEWHERE ,或者該語句正在阻止刪除您認為應該刪除的行。如果您可以在應用程序中查看程式碼,請通過編輯連結將執行(或執行)刪除的程式碼添加到您的問題中。如果您無權訪問程式碼,則可以使用SQL Server Profiler執行跟踪,以便您可以“查看”您的應用程序向伺服器發出的語句,以確定應用程序正在做什麼。

可能存在一些應用程序級數據問題阻止應用程序執行刪除。例如,如果沒有強制引用完整性的主/外鍵關係,則 DELETE FROM 語句可能在刪除中使用連接,該連接有效地排除了由於這些行被孤立而被刪除的行。舉個例子,看看這個:

USE tempdb;

IF OBJECT_ID(N'dbo.Child', N'U') IS NOT NULL
DROP TABLE dbo.Child;
IF OBJECT_ID(N'dbo.Parent', N'U') IS NOT NULL
DROP TABLE dbo.Parent;

CREATE TABLE dbo.Parent
(
   parent_id int NOT NULL
       CONSTRAINT Parent_pk
       PRIMARY KEY CLUSTERED
   , parent_data varchar(50) NOT NULL
);

CREATE TABLE dbo.Child
(
   child_id int NOT NULL
       CONSTRAINT Child_pk
       PRIMARY KEY CLUSTERED
   , parent_id int NOT NULL
   , child_data varchar(10) NOT NULL
);

INSERT INTO dbo.Parent (parent_id, parent_data)
VALUES (1, 'A')
   , (2, 'B');

INSERT INTO dbo.Child (child_id, parent_id, child_data)
VALUES (1, 1, 'C')
   , (2, 1, 'D')
   , (3, 2, 'E')
   , (4, 2, 'F')
   , (5, 3, 'G')
   , (6, 3, 'H');

SELECT *
FROM dbo.Child;
╔══════════╦═══════════╦════════════╗
║ child_id ║ parent_id ║ child_data ║
╠══════════╬═══════════╬════════════╣
║ 1 ║ 1 ║ C ║
║ 2 ║ 1 ║ D ║
║ 3 ║ 2 ║ E ║
║ 4 ║ 2 ║ F ║
║ 5 ║ 3 ║ G ║
║ 6 ║ 3 ║ H ║
╚══════════╩═══════════╩════════════╝

現在,如果我們想從 中刪除所有行dbo.Child,我們可以使用這個 delete 語句刪除在父表中具有父級的所有子行:

DELETE FROM dbo.Child
FROM dbo.Child c
INNER JOIN dbo.Parent p ON c.parent_id = p.parent_id;

如果我們在表中有正確定義的外鍵dbo.Child,則第 5 行和第 6 行將永遠無法存在,但是由於我們沒有良好的關係完整性,行可以存在於沒有父級的子表中,就像你從SELECT上面的刪除執行後執行的這條語句可以看出:

SELECT *
FROM dbo.Child;
╔══════════╦═══════════╦════════════╗
║ child_id ║ parent_id ║ child_data ║
╠══════════╬═══════════╬════════════╣
║ 5 ║ 3 ║ G ║
║ 6 ║ 3 ║ H ║
╚══════════╩═══════════╩════════════╝

當 SQL Server 檢測到主數據庫(目前線上並為客戶端提供服務的數據庫)損壞時,它將通過自動頁面修復從鏡像數據庫中傳輸損壞的頁面,以嘗試自動修復數據庫。自 SQL Server 2005 Service Pack 1 起,自動頁面修復就已可用,此時鏡像正式成為受支持的選項。

由於您在執行DBCC CHECKDB時沒有報告任何腐敗,我幾乎可以 100% 確定您沒有遇到腐敗。

情況是傳遞給數據庫的簡單刪除命令不會刪除某些表中的數據。我真的必須通過 SQL Server Management Studio 進入並發出刪除命令來清除這些表。

如果這使您認為數據庫已損壞,那麼您的想法不正確。您如何確定數據庫已損壞。我只是按照你發布的內容進行

我的第一個問題是我是否應該信任數據庫備份以包含 DBCC CHECKDB 會發現的損壞數據。如果備份不儲存損壞,最好的方法是停止然後恢復活動數據庫和鏡像數據庫以獲取 LDF 和 MDF 文件的副本?

腐敗最重要的是為什麼會發生,什麼是原因。如果備份沒有損壞,那麼您很幸運,在這種情況下,您將不得不在同一台伺服器上以不同的名稱恢復數據庫。如果底層子系統嚴重損壞,新恢復的數據庫也可能會損壞。鏡像數據庫也可能已損壞,否則您可以故障轉移到鏡像數據庫(當您並行執行還原時)並查看它是否有效。

最後,如果我在測試中發現損壞,我將如何確定可能顯示損壞的頁面內容?

這取決於損壞的級別和結果為何產生 dbcc checkdb 命令。如果你幸運地執行它,它會產生顯示哪些頁面(頁面 ID)和索引(CI,NCI)已損壞的結果,實際上它有點棘手,你可能需要專家來解決這個問題。

使用事件查看器閱讀 SQL Server 錯誤日誌sp_readerrorlog將為您提供有關損壞的更多資訊。大多數損壞的磁碟子系統是 SQL Server 數據庫損壞的原因

道德:每件事都取決於腐敗程度。只需執行 repair_rebuild 命令即可消除很少的損壞。

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