SQL Server 提供豐富的鎖定提示,讓開發者在 SELECT 語句中精確控制並行存取行為。本文系統整理六大常用提示的行為、適用場景、風險與最佳實務,並說明其如何覆蓋交易隔離等級設定。
| 提示 | 中文名 | 鎖定類型 | 持續時間 | 典型用途 | 風險/副作用 |
|---|---|---|---|---|---|
| NOLOCK | 不加鎖 / 髒讀 | 無鎖定 (Sch-S 除外) | 即時釋放 | 報表查詢、資料探勘、可容忍髒讀 | 讀到未認可資料、資料列可能消失/重複 |
| HOLDLOCK | 保持鎖 / 序列化範圍 | 共享鎖 (Range-S) | 交易結束 | 需在交易中重複讀取相同資料、防止幻讀 | 並行度降低、易死結 |
| UPDLOCK | 更新鎖 | 更新鎖 (U) | 交易/陳述式結束 | 讀取後稍後更新同筆資料、防止轉換死結 | 阻塞其他 U/X 鎖、需在交易中使用 |
| TABLOCK | 表鎖 (共享) | 表級共享鎖 (Tab-S) | 陳述式結束 | 大量讀取、配合 HOLDLOCK 達序列化 | 阻塞所有寫入、大表影響面廣 |
| PAGLOCK | 頁鎖 (預設) | 頁級共享鎖 (Pag-S) | 陳述式結束 | 預設行為、平衡並行與開銷 | 無特殊風險 |
| TABLOCKX | 排他表鎖 | 表級排他鎖 (Tab-X) | 交易/陳述式結束 | 大量載入、重建索引、獨佔維護 | 完全阻塞所有存取、極高衝突 |
-- 單一提示
SELECT * FROM Orders WITH (NOLOCK) WHERE CustID = 1001;
-- 多重提示 (UPDLOCK + HOLDLOCK = 序列化讀取)
SELECT * FROM Accounts WITH (UPDLOCK, HOLDLOCK) WHERE AcctID = 500;
-- 結合索引提示
SELECT * FROM Orders WITH (NOLOCK, INDEX(IX_Orders_CustDate)) WHERE CustID = 1001;
SET TRANSACTION ISOLATION LEVEL 與資料庫預設隔離等級。BEGIN TRAN; SELECT ... WITH (UPDLOCK, HOLDLOCK); UPDATE ...; COMMIT;SERIALIZABLE 隔離等級,防止幻讀。NOLOCK 或設定資料庫 READ_COMMITTED_SNAPSHOT ON (RCSI) 取得陳述式層級快照,無髒讀風險。UPDLOCK, HOLDLOCK 於同一交易內。TABLOCKX 獨佔表,搭配 BULK_LOGGED 復原模式。NOLOCK,財務/庫存資料嚴禁。TABLOCK/TABLOCKX,除非經過負測驗證。-- 資料庫層級啟用 (需獨佔)
ALTER DATABASE YourDB SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE YourDB SET ALLOW_SNAPSHOT_ISOLATION ON;
-- 工作階段層級使用
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN; SELECT * FROM Orders; COMMIT;
RCSI/SI 提供無鎖定讀取且保證一致性,為現代 OLTP 首選架構。