鎖是多使用者環境下保證資料一致性與隔離性的核心機制。SQL Server 採用多粒度、動態升級的鎖架構,本文系統解析鎖粒度、鎖模式、常見並發問題與觀察工具。
| 異常 | 描述 | 生活化比喻 |
|---|---|---|
| 遺失更新 | 兩筆交易讀同一資料並更新,後寫入覆蓋先寫入 | 兩編輯同一文件,後存檔者蓋掉先前修改 |
| 髒讀 | 讀取未提交的修改資料 | 編輯中文件被複製分發,編輯者後來取消修改,分發版成廢稿 |
| 不可重複讀 | 同一交易兩次讀取同一資料,結果不同 | 編輯者修改文件,審核者前後讀到不同版本 |
| 幻影讀 | 交易讀取範圍,另一交易插入新列滿足條件,重讀多出列 | 編輯完章節,作者新增章節,合併時發現遺漏 |
| 粒度 | 資源 | 並發度 | 系統開銷 | 典型場景 |
|---|---|---|---|---|
| 列 (Row) | 單一資料列 | 最高 | 最高 (鎖數量多) | OLTP 高並發點查/更新 |
| 頁 (Page, 8KB) | 資料/索引頁 | 中 | 中 | 舊版預設、範圍掃描 |
| 區 (Extent, 8頁) | 配置單位 | 低 | 低 | 建表/建庫空間配置 |
| 表 (Table) | 整張表 | 最低 | 最低 (鎖少) | 大量載入、DDL、掃描全表 |
| 資料庫 (Database) | 整個資料庫 | 極低 | 極低 | 資料庫還原、單一使用者模式 |
動態鎖升級:當單一交易持有鎖數量達閾值 (約 5000),SQL Server 自動將列/頁鎖升級為表鎖,降低記憶體壓力。閾值與升級行為由引擎自動決定,不可手動設定。
| 模式 | 縮寫 | 相容性 | 用途 |
|---|---|---|---|
| 共享鎖 | S | 與 S、U 相容;與 X、BU 不相容 | SELECT 讀取 |
| 更新鎖 | U | 與 S 相容;與 U、X、BU 不相容 | UPDATE/DELETE 尋找階段,防死鎖 |
| 排他鎖 | X | 與所有鎖不相容 | INSERT/UPDATE/DELETE 修改階段 |
| 意圖鎖 | IS/IU/IX | 層級相容性指示 | 表/頁層級表達下層加鎖意圖 |
| 結構鎖 | Sch-S / Sch-M | Sch-S 與所有鎖相容(除 Sch-M);Sch-M 獨佔 | DDL (Sch-M) / 查詢編譯 (Sch-S) |
| 大量更新鎖 | BU | 允許並發 BULK INSERT;阻擋非大量操作 | BULK INSERT + TABLOCK |
若無 U 鎖:兩交易先取 S 鎖讀取,再嘗試升級為 X 鎖 → 互相等待對方釋放 S 鎖 → 死鎖。
有 U 鎖:尋找階段直接取 U 鎖 (與 S 相容、與 U/X 不相容),同一時間僅一交易持有 U 鎖,確定修改再升級為 X,打破循環等待條件。
管理 → 目前活動 → 鎖/處理序 圖形化檢視、刷新、終止處理序。EXEC sp_lock [spid] 列出指定/所有處理序持有鎖。SELECT resource_type, resource_description, request_mode, request_status, request_session_id
FROM sys.dm_tran_locks;
SQL Server 死鎖偵測器定期掃描等待圖,發現環狀等待時選擇「犧牲成本最低」的受害者 (通常是執行最少工作、最易重試的交易),回滾並回傳錯誤 1205。應用層需捕捉 1205 並實作重試邏輯。
ROWLOCK, UPDLOCK, HOLDLOCK, TABLOCKX 等) 精準控制,但濫用會適得其反。READ_COMMITTED_SNAPSHOT 以版本存放取代共享鎖,大幅降低讀寫封鎖。深入理解鎖機制,才能在高並發系統中寫出高效、穩定的資料存取邏輯。