sp_MSforeachdb 在執行 DBCC CHECKDB 時繼續失敗
我有以下維護腳本
DECLARE @sql NVARCHAR(30) = 'DBCC CHECKDB(?)' EXEC sp_MSforeachdb @sql
這會檢查每個數據庫是否損壞。我已經在我的測試伺服器上執行了這個,我故意損壞了一個數據庫,並且正如預期的那樣,該
DBCC CHECKDB
數據庫的錯誤,然而,這會結束腳本,所以所有其他尚未檢查的數據庫都未選中。有沒有辦法讓腳本繼續出錯,以便檢查剩餘的數據庫?
我也試過Aaron Bertrand 的 sp_foreachdb發現行為是一樣的
1:https ://www.mssqltips.com/sqlservertip/2201/making-a-more-reliable-and-flexible-spmsforeachdb/以及Ola.Hallengren 的 SQL Server 完整性檢查,使用
DatabaseIntegrityCheck @Databases = 'ALL_DATABASES'
再次給出相同行為的命令我注意到管理工作室在底部也顯示“斷開連接”
我知道這是一篇舊文章,但我會添加這個答案以防有人遇到它。最可能的原因是錯誤非常嚴重(其嚴重性為 20 或更高,最有可能是 22、23 或 24)以致實際連接已終止並且應用程序已斷開連接。問題和其他答案以及 Ola 的腳本中提到的任何 For Each DB 選項都會發生這種情況。
一種解決方案是使用 PowerShell 為您執行完整性檢查。創建一個獲取數據庫列表的腳本(例如使用Invoke-SqlCmd),然後使用 foreach 循環遍歷 DB 並執行完整性檢查。
由於每次迭代都會建立一個新連接,因此任何故障都不應影響剩餘的數據庫。您將需要從 Invoke-SqlCmd 輸出 SQL 錯誤,並在 foreach 循環中使用 try-catch 塊來優雅地處理來自 SQL Server 的終止錯誤,然後再繼續下一個數據庫。
我已經針對導致錯誤 sev 23 的故意損壞的數據庫測試了以下 PowerShell 腳本,它工作正常。您還可以通過替換第二個 Invoke-SqlCmd 的 Query 參數中的值來針對單個數據庫使用 Ola 腳本以提高靈活性。
$Databases = Invoke-SqlCmd -ServerInstance SERVERNAME -Database master -Query "SELECT [name] AS [Database] FROM sys.databases ORDER BY 1 DESC;" foreach ($DB in $Databases) { Write-Output "Processing $($DB.Database)..." try { Invoke-SqlCmd -ServerInstance SERVERNAME -Database master -Query "DBCC CHECKDB ([$($DB.Database)]);" -OutputSqlErrors:$true -Verbose } catch { Write-Output "Error encountered: $($_.Exception.Message)" } } Write-Output "Complete."
由於我無法有意識地提供一個未記錄、不受支持且可能跳過數據庫的解決方案,因此請使用我的替代品,嘗試添加
TRY/CATCH
:EXEC master.dbo.sp_foreachdb @command = N' BEGIN TRY DBCC CHECKDB(?) WITH NO_INFOMSGS, ALL_ERRORMSGS; END TRY BEGIN CATCH PRINT ''? failed.''; END CATCH';
但是,根據錯誤的嚴重程度,它可能會切斷連接。如果您將兩個數據庫設置為離線然後添加參數,則上述方法有效
@state_desc
(因為該過程自然會跳過離線數據庫,所以這是必需的):ALTER DATABASE db1 SET OFFLINE WITH ROLLBACK IMMEDIATE; ALTER DATABASE db2 SET OFFLINE WITH ROLLBACK IMMEDIATE; GO EXEC master.dbo.sp_foreachdb @command = N' BEGIN TRY DBCC CHECKDB(?) WITH NO_INFOMSGS, ALL_ERRORMSGS; END TRY BEGIN CATCH PRINT ''? failed.''; END CATCH', @state_desc = N'OFFLINE';
輸出:
db1 failed. db2 failed.
如果
TRY/CATCH
在您的場景中仍然失敗,您可能希望停止正在執行的操作並直接處理該問題,然後再繼續對其他數據庫進行“一切正常”檢查,或者至少在您確定存在問題的數據庫後,使用@exclude_list
First Responders Kit 中添加的參數完全繞過它: