阻塞是資料庫並發控制的必然產物,但過度阻塞會嚴重拖垮系統回應。本文系統梳理阻塞定義、五大常見成因場景、排查工具鏈、應用層預防準則,助您從根源消除阻塞隱患。
徵兆:大量 UPDATE/DELETE 無 WHERE 或全表掃描,升級為資料表鎖 (TAB),阻塞所有讀寫。
對策:優化索引消除掃描;拆分大批次操作 (分塊提交);錯峰執行維護作業;啟用 RCSI (Read Committed Snapshot Isolation) 讓讀不阻寫。
徵兆:游標逐行處理長時間持有共享鎖,阻塞並發寫入。
對策:改用集合式操作 (JOIN/APPLY/窗口函數);必須用游標時指定 FAST_FORWARD (唯讀、順向) 減少鎖持有時間。
徵兆:應用呼叫 SQLCancel() 取消查詢,但未發送 ROLLBACK/COMMIT,交易保持開啟持續持有鎖。
對策:應用程式務必在 catch/finally 區塊中顯式 ROLLBACK;連線池啟用 Connection Reset (預設開啟) 自動清理。
徵兆:中途關閉 DataReader/DataSet,留下未讀資料流導致共享鎖殘留。
對策:using 區塊確保 Close() 執行;或一次性讀入記憶體 (DataTable.Load()) 再處理業務邏輯。
徵兆:單一應用執行緒開多連線非同步提交,結果處理順序導致循環等待。
對策:單執行緒串行化多連線操作;使用繫結連線 (sp_getbindtoken) 共享交易空間;設定查詢/鎖逾時中斷死循環。
sp_who2 / sp_whoisactive (推薦) 查看阻塞鏈。sys.dm_exec_requests、sys.dm_tran_locks、sys.dm_os_waiting_tasks 聯查鎖資源與等待類型。DBCC INPUTBUFFER(spid) 取得阻塞頭 SQL 文本;結合 Query Store / Extended Events 分析計畫。WHERE name LIKE '%input%')。CommandTimeout / SET LOCK_TIMEOUT。