檢測和修復 SQL Server 鏡像數據庫上的數據庫損壞
我是我現在的公司的新手,我們有系統管理員,但沒有 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 命令即可消除很少的損壞。