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

SQL Server 併發鎖衝突應對:NOLOCK 與 READPAST 行為差異、適用場景與業務容忍度評估

     編輯:關於SqlServer

核心原則:業務容忍度優於技術手段

非金融核心業務,查詢結果「多幾行」或「少幾行」通常可接受。優先評估業務邏輯能否容忍髒讀或漏讀,而非盲目追求「不加鎖怎麼查」。

NOLOCK vs READPAST 行為對比

行為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; -- 無結果(跳過鎖定行)

適用場景決策樹

  1. 報表/大屏/BI 查詢:數據波動可接受 → NOLOCK 或設置會話 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED。
  2. 佇列消費/任務調度:搶單邏輯,已被處理的行直接跳過 → READPAST 配合 UPDLOCK, ROWLOCK 實現無鎖佇列:
    SELECT TOP 1 * FROM TaskQueue WITH (READPAST, UPDLOCK, ROWLOCK) WHERE Status = 0
  3. 核心交易/對賬/審計:嚴禁 使用上述提示,必須保證強一致性。
  4. 高併發讀寫混合:優先優化索引、縮短事務、啟用 READ_COMMITTED_SNAPSHOT(行版本控制),從根源減少阻塞,而非依賴提示。

風險提示

  • NOLOCK 可能讀到半寫入的數據頁(頁分裂中),導致列值錯亂、甚至報 601/602 錯誤。
  • READPAST 導致結果集不完整,聚合統計(SUM/COUNT)偏低。
  • 兩者均不尊重外鍵/約束一致性,可能返回邏輯上不存在的組合。
  • 查詢計劃中出現 Table Scan 時,NOLOCK 效果差,因仍需掃描頁面頭。

最佳實踐總結

「能用索引和隔離級別解決的阻塞,不用 Hint;必須用 Hint 時,在代碼註釋寫明業務容忍理由,並加單元測試驗證結果偏差範圍。」

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved