SQL2008中SQL應用之-阻塞(Blocking)應用分析

當一個數據庫會話中的事務正鎖定一個或多個其他會話事務想要讀取或修改的資源時,會產生阻塞(Blocking)。

通常短時間的阻塞沒有問題,且是較忙的應用程序所需要的。然而,設計糟糕的應用程序會導致長時間的阻塞,這就不必要地鎖定了資源,而且阻塞了其他會話讀取和更新它們。

在SQL Server中,一個阻塞的進程會無限期地保持阻塞,或者直到它超時(根據set lock_timeout)、服務器關閉、進程被殺死、連接完成了更新或者其他發生在原始事務上的操作導致它釋放了資源上的鎖。

發生長時間阻塞的原因如下:

1、在一個沒有索引的表上的過量的行鎖會導致SQL Server得到一個鎖,從而阻塞其他事務。

2、應用程序打開一個事務,并在事務保持打開的時候要求用戶進行反饋或交互。這通常是讓最終用戶在GUI上輸入數據而保持事務打開的時候發生。此時,事務引用的任何資源都會被占據。

3、事務BEGIN后查詢的數據可能在事務事務開始前被調用

4、查詢不恰當地使用鎖定提示。例如,應用程序僅使用很少的行,但卻使用一個表鎖提示

5、應用程序使用長時間運行的事務,在一個事務中更新了很多行或很多表(把一個大量更新的事務變成多個更新較少的事務有助于改善并發性)

下面我們演示使用SQL Server動態管理視圖sys.dm_os_waiting_tasks找出阻塞進程,該視圖用于代替早期SQL Server版本中的系統存儲過程sp_who

找出阻塞的進程后,我們使用sys.dm_exec_sql_text動態管理函數和sys.dm_exec_Connections(DMV)找出正在執行的查詢的SQL文本,然后強制結束進程。

強制結束進程,我們使用kill命令。kill的用法,請參看MSDN:

該命令有三個參數:

session ID 要終止的進程的會話 ID。session ID 是在建立連接時為每個用戶連接分配的唯一整數 (int)。在連接期間,會話 ID 值與該連接捆綁在一起。連接結束時,則釋放該整數值,并且可以將它重新分配給新的連接。使用 KILL session ID 可終止與指定的會話 ID 關聯的常規非分布式事務和分布式事務。
UOW 標識分布式事務的工作單元 (UOW) ID。UOW 是可從 sys.dm_tran_locks 動態管理視圖的 request_owner_guid 列中獲取的 GUID。也可從錯誤日志中或通過 MS DTC 監視器獲取 UOW。有關監視分布式事務的詳細信息,請參閱 MS DTC 文檔。使用 KILL UOW 可終止孤立的分布式事務。這些事務不與任何真實的會話 ID 相關聯,與虛擬的會話 ID = ‘-2’ 相關聯??墒箻俗R孤立事務變得更為簡單,其方法是查詢 或 動態管理視圖中的會話 ID 列。
WITH STATUSONLY 生成由于更早的 KILL 語句而正在回滾的指定 session ID 或 UOW 的進度報告。KILL WITH STATUSONLY 不終止或回滾 session ID 或 UOW,該命令只顯示當前的回滾進度。

在第一個查詢窗口:
代碼如下:
BEGIN TRAN
UPDATE Production.ProductInventory
SET Quantity = 400
WHERE ProductID = 1 AND
LocationID = 1

第二個窗口:
代碼如下:
UPDATE Production.ProductInventory
SET Quantity = 406
WHERE ProductID = 1 AND
LocationID = 1

第三個窗口:
代碼如下:
SELECT blocking_session_id, wait_duration_ms, session_id
FROM sys.dm_os_waiting_tasks
WHERE blocking_session_id IS NOT NULL

/*
blocking_session_id wait_duration_ms session_id
52 23876 54
*/

可以看出是SessionID為52的會話阻塞了SessionID為54的會話。

那么,52正在干啥壞事呢?在第三個窗口中執行:
代碼如下:
SELECT t.text
FROM sys.dm_exec_connections c
CROSS APPLY sys.dm_exec_sql_text (c.most_recent_sql_handle) t
WHERE c.session_id = 54

/*
text
(@1 int,@2 tinyint,@3 tinyint)UPDATE [Production].[ProductInventory] set [Quantity] = @1 WHERE
[ProductID]=@2 AND [LocationID]=@3
*/

注意:這并不是第一個查詢窗口中的原SQL語句,SQL Server進行了自動參數化計劃緩存(預編譯)。
我們強制終止會話。在第三個窗口中執行:
代碼如下:
kill 52

注意:窗口一的語句和窗口二的語句均終止。

提示:第三個語句中,使用

參數以毫秒為單位。超過時會返回鎖定錯誤。示例:

在第一個窗口中執行:
代碼如下:
USE AdventureWorks
BEGIN TRAN
UPDATE Production.ProductInventory
SET Quantity = 400
WHERE ProductID = 1 AND
LocationID = 1

在第二個窗口中執行:
代碼如下:
USE AdventureWorks
SET LOCK_TIMEOUT 1000
UPDATE Production.ProductInventory
SET Quantity = 406
WHERE ProductID = 1 AND
LocationID = 1

/*
1秒后的執行結果
Msg 1222, Level 16, State 51, Line 3
Lock request time out period exceeded.
The statement has been terminated.
*/

解析:在這個示例中,我們設置了鎖超時時間為1000毫秒,即1秒。這個設置不會影響資源被進程占有的時間,只會影響等待另一個進程釋放資源訪問的時間。

? 版權聲明
THE END
喜歡就支持一下吧
點贊9 分享