空閒的 SQL Server 連接如何導致阻塞?
我有一個繁忙的事務性 SQL Server (2012),它有間歇性阻塞問題(每隔幾天左右)。我一直在使用擴展事件來擷取阻塞程序報告,但這些表明阻塞程序似乎是空閒的,輸入緩衝區為
use [_dummy]
.連接到該伺服器的應用程序使用多個數據庫,因此 _dummy 是一個空白數據庫,連接池打開連接到該數據庫;根據需要切換數據庫上下文。
我認為發生的事情是查詢在獲得鎖後超時,而不是回滾事務,並且應用程序正在將連接釋放回連接池,連接池在由於打開事務而發生問題之前重置數據庫上下文. 為了嘗試解決我更改了使用者連接設置,以便預設情況下啟用 XACT_ABORT,認為這會導致超時事務自動回滾,但這似乎並沒有解決問題。
是否還有其他可能導致空閒連接(.NET 連接池的一部分)阻止其他查詢的東西?有什麼方法可以擷取有關在阻塞程序上執行的最後一個查詢的更多資訊?
注意:我也在監視死鎖,被阻塞的程序有時會被阻塞幾分鐘,但不會變成死鎖。
如果您對 Data Collector 感到滿意,則可以下載並安裝ExtendedTSQLCollector並設置一個收集集以使用 XE 擷取阻塞和死鎖事件。我有一篇部落格文章解釋瞭如何做到這一點。
為了收集導致阻塞的休眠 SPID,您可以設置另一個收集集(或同一收集集中的其他收集項)來擷取有關這些 SPID 的資訊。您可以使用在此答案中找到的查詢。您還可以調整查詢以提取有關睡眠 SPID 鎖定的對象的資訊。
使用此設置,您應該可以輕鬆辨識阻塞 SPID。除了發出的最後一個命令之外,您不會輕易辨識的是睡眠 SPID 在做什麼。但是,通過收集到的資訊,您可以設置更具體的內容,例如使用環形緩衝區目標過濾應用程序名稱和/或主機名(或任何有意義的內容)的 XE 會話,並在空閒之前探勘它執行的批處理。
祝你好運!
輸入緩衝區是
use [_dummy]
。連接到該伺服器的應用程序使用多個數據庫,因此 _dummy 是一個空白數據庫,連接池打開連接到該數據庫;根據需要切換數據庫上下文。
嗯。您確定嗎?建立連接時,假設使用了 Connection String 關鍵字“database”(或其同義詞之一)(即
database=_dummy;
),那麼您將看不到USE [_dummy]
語句。如果指定為連接的一部分,則不會執行任何命令來設置連接數據庫。但是,如果您SqlConnection.ChangeDatabase()
在連接後使用,那麼您會看到該USE
語句。因此,要麼設置不正確,程式碼確實沒有連接到_dummy
,而是_dummy
在連接時更改為(不完全相同,特別是如果您試圖避免連接池碎片),或者某人或某個程序正在執行該USE
語句。另外,我不確定為什麼,如果這真的是應用程序這樣做,您甚至會看到該
USE
聲明。您應該看到SqlCommand
對象正在執行什麼。如果此 Session 確實是應用程序連接池的一部分,那麼即使連接被“關閉”,您仍然應該看到執行時送出的最後一批查詢DBCC INPUTBUFFER
。當然,應用程式碼可能會在關閉連接之前切換數據庫,儘管我不明白為什麼有人會故意這樣做。我認為發生的事情是查詢在獲得鎖後超時,而不是回滾事務,並且應用程序正在將連接釋放回連接池,連接池在由於打開事務而發生問題之前重置數據庫上下文.
假設事務是
BEGIN TRAN;
通過 a開始的SqlCommand
,那麼是的,直到關於“在由於打開的事務而發生問題之前重置數據庫上下文”的部分。這是對連接池如何工作的常見誤解。關閉連接時不會重置會話。它在 Connection 再次打開時重置,並執行第一個SqlCommand
。僅僅打開 Connection 是不夠的sp_reset_connection
。因此,如果應用程式碼
try / catch / finally
邏輯能夠乾淨地處理超時異常並且連接 a) 返回到池中,並且 b) 在幾分鐘內(或者無論您看到多長時間)都沒有再次使用阻塞發生),那麼事務及其鎖很可能會在那里呆一會兒,直到重新打開連接並執行某些操作,或者應用程序結束,或者池中的連接超時,或手動清除連接池。當我有時間的時候,我打算在部落格上介紹與連接池相關的所有各種行為和技術細節。但現在我至少記錄了其中一些與臨時對像有關的內容:會話、臨時對象和來世