Sql-Server
SQL Server 完整性檢查錯誤
我已經在我的一個SQL 2012 伺服器上實施了 Ola 的 SQL Server 完整性檢查,並創建了一個 SQL 代理作業來執行它。
每次我執行它都會失敗,但是當我手動執行下面的程式碼時它執行良好。
我還為作業創建了一個輸出文件,顯示完整性檢查確實在我的所有數據庫上執行。
execute [dbo].[DatabaseIntegrityCheck] @Databases = 'ALL_DATABASES'
失敗步驟的輸出在這裡,不包括顯示我的數據庫名稱的所有文本:
Date 22/06/2020 14:11:26 Log Job History (Integrity check) Step ID 1 Server SQL-2012 Job Name Integrity check Step Name DatabaseIntegrityCheck Duration 00:05:37 Sql Severity 16 Sql Message ID 50000 Operator Emailed Operator Net sent Operator Paged Retries Attempted 0 The step failed.
有什麼想法嗎?
似乎 SQL Server 代理將報告作業失敗,其中步驟遇到嚴重性不是 0、1 或 10 的錯誤(請參見下面的展示)。我手頭沒有 2012 實例 - 使用 SQL Server 2016 進行了測試。在您的情況下,出現嚴重性為 16 的損壞錯誤 (8956)。作業執行顯示失敗應該是意料之中的。我懷疑基於快速搜尋結果(像這樣),錯誤 8956 之前會出現錯誤 8952。 我建議診斷/解決損壞原因。
額外細節:
在您的評論中,您提到記錄了錯誤 8956。這是嚴重級別 16 的錯誤:
關於我之前關於 SQL Server 代理作業失敗的評論 - 這是由 DatabaseIntegrityCheck 呼叫的 CommandExecute 的相關位:
DECLARE @sp_executesql nvarchar(max) = QUOTENAME(@DatabaseContext) + '.sys.sp_executesql' . . . IF @Mode = 1 AND @Execute = 'Y' BEGIN EXECUTE @sp_executesql @stmt = @Command SET @Error = @@ERROR SET @ReturnCode = @Error END . . .
展示:
因此,為了證明如果步驟遇到嚴重 16 錯誤,作業將被報告失敗,可以創建一個如下所示的儲存過程,觸發嚴重 16 錯誤並從代理作業呼叫 -
CREATE PROCEDURE sp_TestDupObject AS BEGIN DECLARE @Error INT = 0 , @sp_executesql nvarchar(max) = QUOTENAME(DB_NAME()) + '.sys.sp_executesql' , @SQL NVARCHAR(512) = 'CREATE TABLE #Table(Column1 INT) --Will fail with Msg 2714, Level 16 (There is already an object named ''#table'' in the database) CREATE TABLE #Table(Column1 INT)' EXECUTE @sp_executesql @stmt = @SQL SET @Error = @@ERROR RETURN @Error END
下面是使用 RAISERROR 迭代嚴重性 0-18 的更全面的展示。首先,顯示嚴重性為 0、1 和 10 的作業成功的結果截圖;所有其他人的失敗:
--Create the job using default options USE [msdb] GO DECLARE @jobId BINARY(16) , @CurrentUser SYSNAME = SUSER_SNAME() EXEC msdb.dbo.sp_add_job @job_name=N'TestAgentSevTolerance', @enabled=1, @category_name=N'[Uncategorized (Local)]', @owner_login_name= @CurrentUser, @job_id = @jobId OUTPUT GO EXEC msdb.dbo.sp_add_jobserver @job_name=N'TestAgentSevTolerance', @server_name = @@SERVERNAME GO EXEC msdb.dbo.sp_add_jobstep @job_name=N'TestAgentSevTolerance', @step_name=N'Raiserror', @step_id=1, @cmdexec_success_code=0, @on_success_action=1, @on_fail_action=2, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'DECLARE @ErrorString NVARCHAR(50) , @CurrentSev TINYINT , @CurrentTestRun TINYINT SELECT @CurrentTestRun = MAX(TestRun) FROM AgentTest SELECT @CurrentSev = MAX(Severity) FROM AgentTest WHERE TestRun = @CurrentTestRun SET @ErrorString = ''This is a test error: Severity '' + CAST(@CurrentSev AS CHAR(2)) + '' State 1'' RAISERROR(@ErrorString, @CurrentSev, 1) -- <<<<<<< This is the heart of what is being demonstrated UPDATE AgentTest SET JobCompleted = 1 WHERE TestRun = @CurrentTestRun AND Severity = @CurrentSev', @database_name=N'SQLAgentErrorSevToleranceTest', @flags=0 GO USE [msdb] GO EXEC msdb.dbo.sp_update_job @job_name=N'TestAgentSevTolerance', @enabled=1, @start_step_id=1 GO USE [SQLAgentErrorSevToleranceTest] GO --Creating as proc so executing (in loop if desired) separately from rest of script easy --Just iterates from MinSev to MaxSev calling job, which will in turn call RAISERROR with each sev NumberRuns times CREATE OR ALTER PROCEDURE usp_RunTest (@NumberRuns TINYINT = 1 , @MinSev TINYINT = 0 , @MaxSev TINYINT = 18)--(Side note - Error sev > 18 can only be specified by sysadmin and must use WITH LOG) AS BEGIN --Sanity checking parameter values since, even though this is only for demo purposes, putting online... IF(@MaxSev > 18 OR @MinSev > 18) BEGIN RAISERROR('Please specify int value from 0 to 18. Error sev > 18 can only be specified by sysadmin and must use WITH LOG', 0, 1) RETURN END IF(@MinSev < 0 OR @MaxSev < 0) BEGIN RAISERROR('Negative numbers are invalid. Please specify int value from 0 to 18.', 0, 1) RETURN END IF(@MinSev > @MaxSev) BEGIN RAISERROR('The @MinSev must be <= @MaxSev. Both must be between 0 to 18 inclusive.', 0, 1) RETURN END DECLARE @Severity TINYINT = @MinSev , @RetCode INT = 0 , @BusyRetry TINYINT = 0 , @TestRun TINYINT = 0 , @PrintString VARCHAR(128) WHILE(@NumberRuns > 0) BEGIN SELECT @TestRun = CASE WHEN EXISTS ( SELECT 1 FROM [AgentTest] WHERE TestRun IS NOT NULL) THEN MAX(TestRun) + 1 ELSE 1 END FROM [AgentTest] SELECT @Severity = CASE WHEN EXISTS ( SELECT 1 FROM [AgentTest] WHERE TestRun = @TestRun AND Severity IS NOT NULL) THEN MAX(Severity) ELSE @MinSev END FROM [AgentTest] WHERE TestRun = @TestRun WHILE (@Severity <= @MaxSev) BEGIN INSERT INTO [AgentTest](TestRun, Severity) VALUES(@TestRun, @Severity) SET @RetCode = 1 SET @BusyRetry = 2 WHILE (@RetCode <> 0 AND @BusyRetry > 0) BEGIN EXEC @RetCode = [msdb].[dbo].sp_start_job @job_name = N'TestAgentSevTolerance' SET @BusyRetry -= 1 IF(@RetCode <> 0) BEGIN IF(@BusyRetry = 0) BEGIN SET @PrintString = 'Retried job execution twice... moving on...' RAISERROR(@PrintString, 0, 1) WITH NOWAIT BREAK END ELSE --Despite below loop, still encountered error 22022 without this wait (request to run job refused because already running) SET @PrintString = 'WAITING FOR PREVIOUS JOB EXECUTION TO COMPLETE... CURRENT SEVERITY ' + CAST(@Severity AS CHAR(2)) RAISERROR(@PrintString, 0, 1) WITH NOWAIT WAITFOR DELAY '00:00:01' END ELSE BEGIN WHILE EXISTS( SELECT 1 FROM [msdb].[dbo].sysjobactivity activity JOIN [msdb].[dbo].sysjobs jobs ON activity.job_id = jobs.job_id WHERE start_execution_date IS NOT NULL AND stop_execution_date IS NULL AND jobs.name = N'TestAgentSevTolerance' ) BEGIN SET @PrintString = 'WAITING FOR PREVIOUS JOB EXECUTION TO COMPLETE... CURRENT SEVERITY ' + CAST(@Severity AS CHAR(2)) RAISERROR(@PrintString, 0, 1) WITH NOWAIT WAITFOR DELAY '00:00:01.00' END END END --Despite below loop, still encountered error 22022 without this wait (request to run job refused because already running) --WAITFOR DELAY '00:00:01' UPDATE [AgentTest] SET JobFailedToStart = @RetCode WHERE Severity = @Severity AND TestRun = @TestRun SET @Severity += 1 END SET @NumberRuns -= 1 END END GO EXEC usp_RunTest @MinSev = 0, @MaxSev = 18, @NumberRuns = 3 SELECT sql_message_id , sql_severity , CASE run_status WHEN 0 THEN 'Failed' WHEN 1 THEN 'Succeeded' WHEN 2 THEN 'Retry' WHEN 3 THEN 'Canceled' WHEN 4 THEN 'In Progress' END [run_status] , message FROM [msdb].[dbo].[sysjobhistory] hist JOIN [msdb].[dbo].[sysjobs] job ON job.job_id = hist.job_id WHERE job.name = N'TestAgentSevTolerance' AND step_name = N'Raiserror' --Uncomment below two lines to make more obvious the successful job executions --AND run_status = 1 --AND sql_severity NOT IN (0,10) ORDER BY run_time DESC --Uncomment and execute below to clean up --EXEC [msdb].[dbo].sp_delete_job @job_name = N'TestAgentSevTolerance' --USE [master] --GO --DROP DATABASE [SQLAgentErrorSevToleranceTest]