我正在阅读来自的答案 这里 (来自stackoverflow,我认为应该在这里问)

NOLOCK 意味着根本不加锁。

您的查询可能会返回 UPDATE 和 截至单次查询中 UPDATE 之后的部分。

我知道 nolock 不会锁定表,因此其他人可以同时查询。

从它显示的答案和示例来看,它在数据更新时获取数据。

为什么会发生这种情况?

我假设对于正常选择,它会尝试在表上放置锁,因此当执行更新语句时,它会在行或页上放置锁。然后,当我尝试运行 select 语句时,它无法放置锁,直到更新语句锁被释放。

但在这种情况下,因为 select 语句不会尝试对表加锁,所以它可以运行而无需等待 update 语句释放锁?

有帮助吗?

解决方案

这并不完全正确 NOLOCK 意味着根本不加锁。在此提示下的查询仍将进行 Sch-S 锁和(可能 HOBT 锁)。

在下面 read committed SQL Server 的隔离级别将(通常) 取行级别 S 锁定并在读取数据后立即释放它们。这些都是不兼容的 X 锁定未提交的更新,从而防止脏读。

在链接答案的示例中 SELECT 查询在遇到修改的行时不会被阻止,因此很可能读取部分更新。

默认情况下也可能发生 read committed 隔离级别也是如此 SELECT 读取一些具有“之前”值的行和其他具有“之后”值的行。只需要设计一种情况

  1. 选择查询读取行的值 R1 并释放其 S
  2. 更新查询更新 R2 并采取 X
  3. 选择查询尝试读取 R2 并被阻止。
  4. 更新查询更新 R1 并采取 X 锁。
  5. 更新事务提交,从而释放其锁并允许 Select 读取 R2

例如,如果 SELECTUPDATE 使用不同的索引来定位感兴趣的行。

例子

CREATE TABLE T
(
X INT IDENTITY PRIMARY KEY,
Y AS -X UNIQUE,
Name varchar(10),
Filler char(4000) DEFAULT 'X'
)


INSERT INTO T (Name)
SELECT TOP 2500 'A'
FROM master..spt_values

现在在一个查询窗口中运行

DECLARE @Sum int

SELECT 'SET @@ROWCOUNT' WHERE 1=0

WHILE (@@ROWCOUNT = 0)
SELECT @Sum = SUM(LEN(Name))
FROM T 
WHERE Y IN (-1, -2500)
HAVING SUM(LEN(Name)) = 3

这将无限循环运行。在另一次跑步中

UPDATE T 
SET Name=CASE WHEN Name = 'A' THEN 'AA' ELSE 'A' END

这可能会停止另一个查询中的循环(如果没有,请重试),这意味着它必须已读取 A,AA 或者 AA,A

其他提示

提示 NOLOCK 等效于交易隔离水平 READ UNCOMMITTED, ,仅限于一个表访问方法的范围。

这会使不承诺出现在您的结果集上的RU? 嗯,实际上是一个问题它不做什么. 。我会在下面解释。

好吧(我知道这是一个简化的简化)MSSQL(在其默认行为中)是锁定引擎 - 这意味着它使用锁定以一致的方式读取/写入数据。在这个过于简化的解释中,MSSQL使用两种锁: 共享锁独家锁.

共享(S)锁定是一个锁定的锁,可以读取资源(可以是行,行甚至整个表)的锁定 - 但不能允许写入它。因此,如果交易T1将S锁定在R1行上,那么所有尝试读取R1的交易都将得到读取,但是尽管S锁定还活着,但没有人可以写信给R1。

独家(X)锁定是共享锁的对应物。它允许对资源的独家访问 - 除了获得X锁定的交易外,没有其他交易可以读取或写入。在上面的示例中,如果T1没有S锁,而是R1上的X锁 除T1以外,没有人可以读取或编写它。

那就是Teory。隔离水平尊重锁,并尊重它们的普遍性和特征。所有,除了 READ UNCOMMITTED. 。简单地给出了一个 *(在此处将您的偏好率不好的口语放在读取的锁上) - 您仍然无法更新一行,另一项交易获得了X锁。它只是说: “我将阅读与查询计划相关的所有内容 - 无视它的锁。”并做。

许可以下: CC-BY-SA归因
不隶属于 dba.stackexchange
scroll top