專案中為追求查詢效能,開發者習慣在所有資料表後加 NOLOCK 或 WITH(NOLOCK)。這真的合適嗎?本文從並發存取問題、鎖機制、隔離層級深入分析,給出科學用法建議。
依資源粒度:表鎖、行鎖、頁鎖 (8KB)、檔案鎖、資料庫鎖。
依相容性:共享鎖 (S, 讀取)、更新鎖 (U, 預防死鎖)、排他鎖 (X, 寫入)。
程式設計師視角:樂觀鎖 (資料庫自管) vs 悲觀鎖 (程式手動控制)。
| 隔離層級 | 髒讀 | 不可重複讀 | 幻讀 | 備註 |
|---|---|---|---|---|
| Read Uncommitted | ✓ | ✓ | ✓ | 等同 NOLOCK,效能最好,一致性最差 |
| Read Committed | ✗ | ✓ | ✓ | SQL Server 預設 |
| Repeatable Read | ✗ | ✗ | ✓ | |
| Serializable | ✗ | ✗ | ✗ | 最高隔離,並發效能最低 |
NOLOCK = READ UNCOMMITTED,不發出共享鎖,允許髒讀。確實能提速,但犧牲資料正確性。
建議僅在以下場景謹慎使用:
資料庫層級啟用 READ_COMMITTED_SNAPSHOT ON 或 ALLOW_SNAPSHOT_ISOLATION ON,讀取不阻塞寫入、寫入不阻塞讀取,統一解決並發衝突,避免到處撒 NOLOCK 的維護惡夢。這才是架構層面的正確解法。
WITH(NOLOCK) 語法;WITH(NOLOCK) 更易搭配索引提示(如 WITH(NOLOCK, INDEX(idx_name)))。