兩行程分別鎖定資源 A、B,又嘗試鎖定對方持有的資源 → 循環等待。SQL Server 自動選擇犧牲者 (成本較低者) 終止並回滾,回傳錯誤 1205。
建立追蹤 →「識別死鎖原因」範本 → 擷取死鎖圖 (deadlock graph) 分析參與物件、SQL、索引。
-- 應用程式端 pseudocode
for retry = 1 to 3
try execute transaction
catch deadlock (1205)
wait Random(50, 200) ms -- 關鍵:隨機避免同步重試再死鎖
end try
end for
拆分複雜交易、減少鎖類型/數量。能拆分就拆分。
條件判斷、變數計算、使用者輸入全部在 BEGIN TRAN 前完成。
-- 讀取時不加鎖
SELECT * FROM table WHERE id = @id;
-- 更新時檢查版本/時間戳
UPDATE table SET col = @val, version = version + 1
WHERE id = @id AND version = @old_version;
-- @@ROWCOUNT = 0 表示資料已被他人修改
預設 Read Committed 易造成共享鎖衝突。評估 Read Committed Snapshot (RCSI) 或 Snapshot Isolation (需 ALLOW_SNAPSHOT_ISOLATION ON)。
READ_ONLY 游標OPTIMISTIC (樂觀並發)SCROLL_LOCKS (悲觀鎖定每列)效能監視器 → SQL Server Locks Object: Average Wait Time (ms) 識別熱點鎖類型 → Profiler 追蹤具體交易。
sp_who2 未文件化但提供 BlkBy、CPU、DiskIO、LastBatch,極實用。
碎片索引導致掃描範圍擴大 → 鎖定更多頁面 → 死鎖機率增。排程 DBCC INDEXDEFRAG/REBUILD + UPDATE STATISTICS。
死鎖無法 100% 根除,但透過應用設計規範 + 資料庫端最佳化 + 監控與重試機制,可將影響降至最低。關鍵在於:鎖定時間最短、範圍最小、順序固定、隔離等級適當。