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

深入掌握 SQL Server 鎖機制與並發控制

     編輯:關於SqlServer

鎖是資料庫在多使用者環境下保證資料完整性與一致性的核心機制。SQL Server 採用動態鎖管理,系統自動分析查詢並在效能與並發間取得平衡。但對於高並發、嚴格一致性需求的系統,深入理解鎖機制並掌握手動控制技巧至關重要。

四大並發問題與鎖的解決

問題描述範例鎖解決方式
遺失更新兩筆交易讀取同一資料並基於舊值更新,後寫入者覆蓋先前更新兩編輯者同時修改同一文件,後存檔者覆蓋先前變更排他鎖 (X-lock) 保護寫入期間資料
髒讀交易讀取未提交的修改資料,若修改者回滾則讀到不存在的資料編輯者修改文件中,他人複製草稿分發;編輯者取消修改,分發版本含無效內容共享鎖 (S-lock) 阻塞讀取未提交資料
不可重複讀同一交易多次讀取同一資料,結果不一致 (被其他交易修改)報表查詢同一帳戶兩次,中間被轉帳交易修改餘額交易隔離等級 REPEATABLE READ
幻覺讀同一交易多次執行相同範圍查詢,結果筆數不同 (被其他交易插入/刪除)統計部門員工數,中間有新進/離職人員範圍鎖、SERIALIZABLE 隔離等級

SQL Server 鎖模式與相容性

主要鎖模式

  • 共享鎖 (S):讀取資料 (SELECT),可相容多個 S 鎖,不相容 X 鎖
  • 更新鎖 (U):預備更新,讀取階段防止死結,轉換為 X 鎖時獨佔
  • 排他鎖 (X):修改資料 (INSERT/UPDATE/DELETE),獨佔,不相容任何其他鎖
  • 意圖鎖 (IS/IX/IU):表達對較低層級資源的鎖意圖,協調階層鎖管理
  • 結構鎖 (Sch-M/Sch-S):DDL 操作 vs 查詢編譯的保護
  • 大量更新鎖 (BU):大量匯入優化

鎖相容性矩陣 (簡化)

既有鎖 \ 要求鎖SUXISIX
S✓✓✗✓✗
U✓✗✗✓✗
X✗✗✗✗✗
IS✓✓✗✓✓
IX✗✗✗✓✓

動態鎖升級

SQL Server 監控鎖數量,當單一陳述式持有鎖超過記憶體閾值 (約 5000 個) 或佔用鎖記憶體超過 40%,嘗試將細粒度鎖 (資料列/頁面) 升級為粗粒度鎖 (資料表/分區)。

控制方式:

  • 追蹤旗標 1211/1224:停用鎖升級 (慎用)
  • ALTER TABLE ... SET (LOCK_ESCALATION = TABLE | AUTO | DISABLE) (SQL 2008+)
  • 設計適當索引減少掃描範圍,降低鎖數量

交易隔離等級與鎖行為

隔離等級髒讀不可重複讀幻覺讀鎖持有時間並發度
READ UNCOMMITTED可能可能可能無 S 鎖最高
READ COMMITTED (預設)防止可能可能讀取瞬間高
REPEATABLE READ防止防止可能交易結束中
SNAPSHOT防止防止防止版本存儲高 (讀不阻寫)
SERIALIZABLE防止防止防止交易結束 + 範圍鎖最低

手動鎖控制技巧

資料表提示

-- 強制使用索引 + 排他鎖
SELECT * FROM Orders WITH (INDEX(IX_OrderDate), UPDLOCK, HOLDLOCK)
WHERE OrderDate > '2024-01-01'

-- 僅讀取已提交資料,不加共享鎖 (髒讀)
SELECT * FROM Products WITH (NOLOCK)  -- 等同 READ UNCOMMITTED

-- 分頁查詢最佳化
SELECT * FROM Sales WITH (READPAST)  -- 跳過被鎖定的資料列
WHERE Region = 'North'
ORDER BY SaleDate DESC
OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY

應用程式鎖

-- 取得應用程式層級互斥鎖
DECLARE @Result INT
EXEC @Result = sp_getapplock 
    @Resource = 'InvoiceGeneration_Batch001',
    @LockMode = 'Exclusive',
    @LockOwner = 'Transaction',
    @LockTimeout = 30000  -- 30 秒逾時

IF @Result >= 0
BEGIN
    -- 執行關鍵業務邏輯
    EXEC sp_releaseapplock @Resource = 'InvoiceGeneration_Batch001', @LockOwner = 'Transaction'
END

監控與疑難排解

  • sys.dm_tran_locks:即時鎖狀態
  • sys.dm_os_wait_stats:等待類型分析 (LCK_M_*)
  • DBCC OPENTRAN:最長執行交易
  • 擴充事件 : lock_deadlock, lock_escalation

最佳實務總結

  1. 預設用 READ COMMITTED,必要時啟用 READ COMMITTED SNAPSHOT (資料庫選項) 實現讀不阻寫
  2. 縮短交易範圍,避免使用者互動在交易中
  3. 固定存取順序 (如:先父表後子表),預防死結
  4. 善用索引縮小掃描範圍,減少鎖爭用
  5. 長時間報表查詢用 NOLOCK 或 SNAPSHOT 隔離
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved