Sql-Server-2016

sp_MSforeachdb 在執行 DBCC CHECKDB 時繼續失敗

  • November 28, 2019

我有以下維護腳本

DECLARE @sql NVARCHAR(30) = 'DBCC CHECKDB(?)'
EXEC sp_MSforeachdb @sql

這會檢查每個數據庫是否損壞。我已經在我的測試伺服器上執行了這個,我故意損壞了一個數據庫,並且正如預期的那樣,該DBCC CHECKDB數據庫的錯誤,然而,這會結束腳本,所以所有其他尚未檢查的數據庫都未選中。

有沒有辦法讓腳本繼續出錯,以便檢查剩餘的數據庫?

我也試過Aaron Bertrand 的 sp_foreachdb發現行為是一樣的

1https ://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_listFirst Responders Kit 中添加的參數完全繞過它:

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