首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 死鎖原理與 6 大避免策略:從四個必要條件到實戰優化

     編輯:關於SqlServer

死鎖四個必要條件(科夫曼條件)

  1. 互斥:資源獨佔(鎖本質)。
  2. 請求並保持:持有鎖的同時請求新鎖。
  3. 非搶佔:持有的鎖只能主動釋放,不可強制剝奪。
  4. 循環等待:進程鏈 P1→R1→P2→R2→...→P1。

打破任一條件即可避免死鎖。數據庫層面主要針對條件 2、4 優化。

六大避免策略

1. 統一訪問順序(破循環等待)

所有事務按相同順序訪問表/行(如先 Supplier 後 Part)。
實施:強制所有寫操作走存儲過程,在過程中固定表訪問順序。

2. 避免事務中用戶交互(縮短持鎖時間)

事務中絕不等待用戶輸入(彈窗、確認、外部 API 同步調用)。
異步化:用戶操作 → 寫請求表 → 後台 Worker 處理 → 通知結果。

3. 事務簡短、單批次執行(減少鎖持有時長)

  • 拆分大事務:批量更新分批提交(如每 5000 行)。
  • 減少網絡往返:將多語句打包在一個批次/存儲過程中執行。
  • 避免在事務中執行耗時計算/外部調用。

4. 降低隔離級別(減少共享鎖持有)

建議:啟用 RCSI(ALTER DATABASE SET READ_COMMITTED_SNAPSHOT ON),讀寫不阻塞,大幅降低死鎖概率,代價是 tempdb 版本存儲開銷。

5. 使用綁定連接(協同鎖共享)

sp_getbindtoken / sp_bindsession 讓同一應用的多個連接共享鎖空間,避免自死鎖。
現代替代:MARS (Multiple Active Result Sets) 或連接池複用單連接上下文。

6. SELECT 加 WITH (NOLOCK) / READ UNCOMMITTED(讀寫不阻塞)

SELECT * FROM Orders WITH (NOLOCK) WHERE CustomerID = 123;

效果:不獲取 S 鎖(獲取 Sch-S 穩定性鎖),允許髒讀。
適用:報表/查詢/統計類只讀場景,嚴禁用於計費/庫存/決策關鍵數據。
替代:RCSI 同樣實現讀不阻塞寫,且無髒讀,優先選 RCSI。

死鎖監控與事後分析

  1. 擴展事件:CREATE EVENT SESSION deadlock_monitor ON SERVER ADD EVENT sqlserver.xml_deadlock_report ADD TARGET package0.event_file (FILENAME=N'Deadlock.xel');
  2. 追蹤旗標 1222/1204:DBCC TRACEON(1222, -1) 記錄死鎖圖到錯誤日志(性能影響較大,慎用)。
  3. 系統健康會話:system_health 默認捕獲死鎖,查詢:
    SELECT CAST(target_data AS XML) FROM sys.dm_xe_session_targets st JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address WHERE s.name = 'system_health';

死鎖圖讀取關鍵點

  • victim:被選中犧牲的進程(通常回滾成本最低者)。
  • resource-list:涉及的鎖資源(KEY/PAGE/OBJECT/HOBT)。
  • process:每個進程的 inputbuf(執行語句)、executionStack(堆棧)、隔離級別、持有/請求鎖模式。
  • 分析重點:鎖模式轉換順序、索引缺失導致表鎖/頁鎖升級、長事務。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
隔離級別髒讀不可重複讀幻讀鎖行為
READ UNCOMMITTEDYYY無 S 鎖(Sch-S)
READ COMMITTED (默認)NYY語句級 S 鎖,讀完即釋放
REPEATABLE READNNY事務級 S 鎖,持有到結束
SERIALIZABLENNN範圍鎖,並發最低
READ COMMITTED SNAPSHOT (RCSI)NNN行版本控制,讀不阻塞寫