Sql-Server

執行此儲存過程會殺死阻塞程序的危險

  • March 10, 2022
use master
GO
CREATE PROC support_KillBlockingProcesses (@RecursiveCount int = NULL)
AS

DECLARE @count int, @spid int, @sql nvarchar(max)
SET @count = ISNULL(@RecursiveCount, 3)

while @count > 0
begin

begin try
 set @spid = (
  select top 1 spid from sysprocesses (nolock)
  where blocked = 0 and spid in (
   select blocked from sysprocesses (nolock) where blocked <> 0
  )
 )
 if @spid > 50
 begin
  set @sql = N'kill ' + cast(@spid as nvarchar(100))
  exec sp_executesql @sql
  --print @sql
 end
end try
begin catch
 --print 'error'
end catch

set @count = @count - 1
end
GO

我看到了這個儲存過程,我想知道當數據庫被凍結時執行這個儲存過程是否有任何危險。我的想法是,即使你殺死的程序很重要,你仍然需要殺死阻塞程序,那麼這樣做真的有什麼後果嗎?知道哪個程序凍結了數據庫有什麼意義?

阻塞不會“凍結數據庫”。它會導致那些碰巧被阻塞的人……被阻塞,直到持有導致阻塞情況的鎖的人釋放該鎖。這與“凍結數據庫”不同。

該程序的危險它會殺死任何阻止者。它殺死的可能是一個非常短暫的阻塞器,阻塞情況只會發生 100 毫秒,但你碰巧只執行了那 100 毫秒。所以,你殺了人卻沒有得到任何東西,因為真正的問題沒有得到解決。而你現在再次執行它,有再次這樣做的風險。

不要只是殺死碰巧阻止其他人的任何人。小心殺戮!

添加到Tibor的答案。

阻塞在數據庫中是正常的,並且一直在發生。阻塞成為問題的地方是它長時間發生,或者最終陷入僵局。雖然我們想避免死鎖,但 SQL 會選擇一個受害者,他們會自行解決。所以,這是一個不同的話題。

現在,假設我有一個通常阻塞 5-10 分鐘的事務,並且在此期間有許多事務等待。使用此過程,您將盲目地殺死有問題的會話,並且永遠不知道您已經這樣做了,或者您有阻塞。作為 DBA,我想知道何時必須終止會話。我想訪問終止會話和掛起回滾的風險。我還想看看可能需要更改哪些內容以防止同一會話將來再次長時間阻塞。

此外,事務現在所做的任何事情都需要回滾。回滾是單執行緒的。這意味著,理論上,如果您有 8 個 CPU,並且您的事務是並行的並且已經執行了 1 小時,那麼回滾可能需要 8 小時。

如果您擔心阻止未被檢測到並對其他程序造成嚴重破壞,請投資一個好的監控工具,並讓它在阻止發生的時間超過定義的時間段時向您發送警報。

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