非金融核心業務,查詢結果「多幾行」或「少幾行」通常可接受。優先評估業務邏輯能否容忍髒讀或漏讀,而非盲目追求「不加鎖怎麼查」。
| 行為 | NOLOCK (READ UNCOMMITTED) | READPAST | 默認 (READ COMMITTED) |
|---|---|---|---|
| 未提交數據 | 可見(髒讀) | 跳過(不顯示) | 阻塞等待 |
| 被排他鎖鎖定的行 | 可見(可能不一致) | 跳過(漏讀) | 阻塞等待 |
| 死鎖風險 | 無(不獲取共享鎖) | 無(跳過鎖定行) | 有(可能成為犧牲者) |
| 一致性保證 | 無 | 僅保證返回行提交一致 | 語句級一致性 |
-- 會話 1
CREATE TABLE t1 (c1 INT IDENTITY, c2 INT);
BEGIN TRAN;
INSERT t1(c2) VALUES (1);
-- 不提交
-- 會話 2
SELECT COUNT(*) FROM t1 WITH (NOLOCK); -- 返回 1
SELECT COUNT(*) FROM t1 WITH (READPAST); -- 返回 0
SELECT COUNT(*) FROM t1; -- 阻塞
-- 會話 1
CREATE TABLE t2 (UserID INT, NickName NVARCHAR(50));
INSERT t2 VALUES (1,'郭紅俊'), (2,'蝈蝈俊');
BEGIN TRAN;
UPDATE t2 SET NickName = '蝈蝈俊.Net' WHERE UserID = 2;
-- 不提交
-- 會話 2
SELECT * FROM t2 WITH (NOLOCK) WHERE UserID = 2; -- 看到 '蝈蝈俊.Net'(髒讀)
SELECT * FROM t2 WITH (READPAST) WHERE UserID = 2; -- 無結果(跳過鎖定行)
NOLOCK 或設置會話 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED。READPAST 配合 UPDLOCK, ROWLOCK 實現無鎖佇列:SELECT TOP 1 * FROM TaskQueue WITH (READPAST, UPDLOCK, ROWLOCK) WHERE Status = 0READ_COMMITTED_SNAPSHOT(行版本控制),從根源減少阻塞,而非依賴提示。NOLOCK 可能讀到半寫入的數據頁(頁分裂中),導致列值錯亂、甚至報 601/602 錯誤。READPAST 導致結果集不完整,聚合統計(SUM/COUNT)偏低。Table Scan 時,NOLOCK 效果差,因仍需掃描頁面頭。「能用索引和隔離級別解決的阻塞,不用 Hint;必須用 Hint 時,在代碼註釋寫明業務容忍理由,並加單元測試驗證結果偏差範圍。」