在 T-SQL 查詢中,可透過 WITH (hint) 語法指定鎖行為,覆寫引擎預設選擇。本文整理 12 種常用鎖提示的語法、效果與適用場景,作為開發與調優快速參考。
| 提示 | 效果 | 適用語句 | 備註 |
|---|---|---|---|
| HOLDLOCK | 持有共享鎖至交易結束 (相當於 SERIALIZABLE) | SELECT | 配合交易實現可序列化讀取 |
| NOLOCK | 不發出共享/排他鎖,允許髒讀 (相當於 READUNCOMMITTED) | SELECT | 唯讀報表、可容忍髒資料時使用 |
| PAGLOCK | 強制使用頁鎖 (而非列/表鎖) | SELECT/UPDATE/DELETE | 大範圍掃描減少鎖數量 |
| READCOMMITTED | 以提交讀隔離語義執行掃描 (預設行為) | SELECT | 明確指定預設行為 |
| READPAST | 跳過已鎖定的列,不等待 (僅 READ COMMITTED 隔離級有效) | SELECT | 工作佇列跳過處理中項目 |
| READUNCOMMITTED | 同 NOLOCK | SELECT | 別名 |
| REPEATABLEREAD | 以可重複讀隔離語義執行掃描 | SELECT | 鎖定讀取範圍至交易結束 |
| ROWLOCK | 強制使用列鎖 (不升級頁/表鎖) | SELECT/UPDATE/DELETE | 高並發點操作,避免升級 |
| SERIALIZABLE | 以可序列化隔離語義執行掃描 (相當於 HOLDLOCK) | SELECT | 範圍鎖防止幻影讀 |
| TABLOCK | 使用表級共享鎖,語句結束釋放;配合 HOLDLOCK 持有至交易結束 | SELECT/INSERT/UPDATE/DELETE | 大量載入、掃描全表 |
| TABLOCKX | 使用表級排他鎖,阻擋所有其他存取,至語句/交易結束 | SELECT/INSERT/UPDATE/DELETE | 獨佔維護、重建索引等 |
| UPDLOCK | 讀取時取更新鎖 (而非共享鎖),持有至語句/交易結束 | SELECT | 先讀後寫模式,防止讀取階段被修改 |
-- 單一提示
SELECT * FROM Orders WITH (NOLOCK) WHERE CustomerID = 'ALFKI';
-- 多重提示 (以空格分隔)
SELECT * FROM Orders WITH (ROWLOCK, UPDLOCK, HOLDLOCK) WHERE OrderID = 10248;
-- 結合查詢提示
SELECT * FROM Orders WITH (INDEX(IX_CustomerID), ROWLOCK) WHERE CustomerID = 'ALFKI';
| 場景 | 推薦提示 | 風險提醒 |
|---|---|---|
| 高併發報表、可容忍髒讀 | NOLOCK / READUNCOMMITTED | 可能讀到中間狀態、重複/遺漏列 |
| 工作佇列取出下一筆待處理 | READPAST + ROWLOCK + UPDLOCK | 需在 READ COMMITTED 隔離級 |
| 先 SELECT 再 UPDATE 同一筆資料 | UPDLOCK + HOLDLOCK (在交易中) | 延長鎖持有時間,評估並發影響 |
| 大量 BULK INSERT / 重建索引 | TABLOCK / TABLOCKX | 完全阻塞並發存取 |
| 防止幻影讀 (範圍查詢) | SERIALIZABLE / HOLDLOCK | 範圍鎖 (Key-Range) 並發度最低 |
NOLOCK 對系統表、索引檢視表、計算欄位可能仍取得結構鎖 (Sch-S)。ROWLOCK 可能導致大量鎖記憶體壓力,觸發升級反而降低效能。SET TRANSACTION ISOLATION LEVEL) 或啟用 READ_COMMITTED_SNAPSHOT,而非大量散佈提示。精準使用鎖提示能解決特定並發痛點,但請視為「手術刀」而非「萬能鑰」,務必在測試環境驗證並發行為後再上線。