首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

SQL Server 事務鎖表導致 SELECT 阻塞:NOLOCK 與 READPAST 解決髒讀/跳過鎖

     編輯:程式設計綜合問答

問題

事務期間表被鎖,SELECT 被阻塞,業務允許讀到未提交資料 (髒讀) 或跳過被鎖行。

方案一:NOLOCK (髒讀)

SELECT * FROM dbo.Orders WITH (NOLOCK) WHERE Status = 1;
-- 等價於
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM dbo.Orders WHERE Status = 1;
  • **優點**:完全不阻塞,效能最好。
  • **缺點**:可能讀到**未提交/已回滾**的資料 (髒讀)、同一查詢中同一行讀兩次或漏讀 (頁分裂)。
  • **適用**:報表、統計、近似查詢、資料不敏感場景。

方案二:READPAST (跳過鎖定行)

SELECT * FROM dbo.Orders WITH (READPAST) WHERE Status = 1;
  • **行為**:遇到被排他鎖 (X) 的行/頁**直接跳過**,不等待、不讀取。
  • **優點**:不阻塞、不髒讀、返回一致性快照 (已提交且未被鎖的行)。
  • **缺點**:結果集**不完整** (漏掉被鎖行)、不支援頁級鎖跳過 (僅行級)。
  • **適用**:佇列處理 (如 `DELETE TOP (1) FROM Queue WITH (READPAST) OUTPUT deleted.*`)、高併發跳過熱點行。

方案三:快照隔離級別 (Row Versioning)

ALTER DATABASE MyDB SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE MyDB SET READ_COMMITTED_SNAPSHOT ON;
-- 連線層級
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
SELECT * FROM dbo.Orders; -- 讀取事務開始時的版本,不阻塞寫入
  • **優點**:讀寫不阻塞、語句級/事務級一致性、無髒讀。
  • **缺點**:`tempdb` 壓力增大、寫入衝突需應用層重試、需資料庫級開啟。

選擇建議

場景推薦
報表/BINOLOCK
任務佇列搶單READPAST + UPDLOCK, ROWLOCK
高併發核心業務READ_COMMITTED_SNAPSHOT (RCSI)
嚴格一致性要求預設 READ COMMITTED (接受阻塞)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved