为什么 UPDATE 会在不相关的行上阻止 SELECT?

发布于 2024-09-29 00:54:45 字数 1482 浏览 3 评论 0原文

有了脚本 [1] 定义的表,我在 SSMS 的 2 个窗口中执行脚本,

--1) first in first SSMS window
set transaction isolation level READ UNCOMMITTED;
begin transaction;
update aaa set Name ='bbb' 
    where id=1;
-- results in "(1 row(s) affected)"
--rollback

并且在 1)

--2)after launching 1)
select * from aaa --deleted comments
where id<>1
--is blocked

独立于 1) 窗口中的事务隔离级别之后,2) 中的 SELECT 被阻止。
为什么?

UPDATE 的隔离级别对其他事务上的语句有影响吗?

最高隔离级别是2)中默认的READ COMMITTED。
没有范围锁归属,SELECT 应该遭受 COMMITTED READS(不可重复读取)和幻象读取(可重复读取)问题 [2]
如何让它受苦?

如何在不阻塞 SELECT 的情况下进行 UPDATE?

[1]

CREATE TABLE aaa
(
    Id int IDENTITY(1,1) NOT NULL,
    Name  varchar(13) NOT NULL
)


insert into  aaa(Name) 
   select '111' union all 
   select '222' union all 
   select '333' union all 
   select '444' union all 
   select '555' union all 
   select '666' union all 
   select '777' union all 
   select '888'  

[2]
单击
后复制并粘贴或添加尾随 ) http://en.wikipedia.org/wiki/Isolation_(database_systems)

更新:< br> SELECT WITH(NOLOCK) 没有被阻止...

更新2:
或者,相同的是,READ UNCOMMITTED

请注意,UPDATE 与 SELECT 行不同。
即使,如果相同,这种行为也与隔离级别的描述相矛盾 [2]

要点是:

  • 假设我不知道还有谁将从同一个(UPDATE-d)表中进行 SELECT 但与更新行无关
  • 以理解隔离级别 [2]

SQL Server 2008 R2 开发

Having the table, defined by script [1], I execute scripts in 2 windows of SSMS

--1) first in first SSMS window
set transaction isolation level READ UNCOMMITTED;
begin transaction;
update aaa set Name ='bbb' 
    where id=1;
-- results in "(1 row(s) affected)"
--rollback

and after 1)

--2)after launching 1)
select * from aaa --deleted comments
where id<>1
--is blocked

Independently on transaction isolation level in 1) window, the SELECT in 2) is blocked.
Why?

Does isolation level for UPDATE have any influence on statements on other transactions?

The highest isolation level is default READ COMMITTED in 2).
No range locks are attributed, SELECT should have suffered from COMMITTED READS (NONREPEATABLE READs) and PHANTOM READS (Repeatable Reads) problems [2]
How to make it suffer?

How can UPDATE be made without blocking SELECT?

[1]

CREATE TABLE aaa
(
    Id int IDENTITY(1,1) NOT NULL,
    Name  varchar(13) NOT NULL
)


insert into  aaa(Name) 
   select '111' union all 
   select '222' union all 
   select '333' union all 
   select '444' union all 
   select '555' union all 
   select '666' union all 
   select '777' union all 
   select '888'  

[2]
Copy&paste or add trailing ) upon clicking
http://en.wikipedia.org/wiki/Isolation_(database_systems)

Update:
SELECT WITH(NOLOCK) is not blocked...

Update2:
or with, what is the same, READ UNCOMMITTED

Note that UPDATE is on different from SELECT row.
Even, if on the same, this behavior contradicts to description of isolation levels [2]

The points are that:

  • suppose I cannot know who else is going to SELECT from the same (UPDATE-d) table but on unrelated to update rows
  • to understand isolation levels [2]

SQL Server 2008 R2 Dev

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

故人爱我别走 2024-10-06 00:54:45

我相信这是因为你没有主键,我认为这会导致锁升级,从而阻止 SELECT。如果您将 PRIMARY KEY 添加到 ID 列,您会注意到,如果您再试一次,SELECT 现在将返回其他 3 行 - 不需要WITH (NOLOCK) 提示。

I believe it's because you don't have a primary key, which I think is resulting in the locks being escalated, hence blocking out the SELECT. If you add a PRIMARY KEY onto the ID column, you will notice that if you try again, the SELECT will return the other 3 rows now - no WITH (NOLOCK) hint needed.

听风吹 2024-10-06 00:54:45

后重复测试

--3)
create index IX_aaa_ID on aaa(id)

在SELECT 2) 仍然被阻止

--4)
drop index IX_aaa_ID on aaa
create unique index IX_aaa_ID on aaa(id)
--or adding primary key constraint   

SELECT 2) 不会被阻止

如果将 2) 修改为如下

--2b)
select * from aaa 
    where id=3 
    --or as
    --WHERE id=2 

所示,即使没有任何索引或 PK,2b) 也不会被阻止。

不过,2b),没有任何索引,在修改 1) UPDATE 以在可序列化下运行后被阻止
但不是在 REPEATABLE READ 或更低的情况下

--1c)  
set transaction isolation level serializable;
--set transaction isolation level REPEATABLE READ;

begin transaction;
update aaa set Name ='bbb' 
    where id=1;
--rollback

所以,看起来多行选择尝试获取不可共享锁?

更新:
好吧,在所有 SELECT 被阻塞的情况下,它都会等待获取 LCK_M_IS
了解这道美食的充分理由

更新2:
嗯,这不是在表上升级的 UPDATE 锁,而是 SELECT(共享)锁(当 SELECT 尝试读取多行时)升级为表锁并且无法授予,因为表已经具有独占(UPDATE) )锁定。

并且索引的存在或不存在与我的主要问题无关

我将这个主题的讨论转移到我提交的建议"不应升级意图行锁如果表已包含排它锁,则为表锁”

Repeating tests after

--3)
create index IX_aaa_ID on aaa(id)

SELECT 2) is still blocked

--4)
drop index IX_aaa_ID on aaa
create unique index IX_aaa_ID on aaa(id)
--or adding primary key constraint   

SELECT 2) is NOT blocked

If to modify 2) as

--2b)
select * from aaa 
    where id=3 
    --or as
    --WHERE id=2 

shows that 2b) is not blocked even in absence of any index or PK.

Though, 2b), without any indexes, is blocked after modifying 1) UPDATE to run under serializable
but not under REPEATABLE READ or lower

--1c)  
set transaction isolation level serializable;
--set transaction isolation level REPEATABLE READ;

begin transaction;
update aaa set Name ='bbb' 
    where id=1;
--rollback

So, it looks like multiple row selection attempts to acquire non-shareable lock?

Update:
Well, in all cases of SELECT being blocked it is waiting to acquire LCK_M_IS
Good reason to uderstand this cuisine

Update2:
Well, it is not UPDATE lock that is escalated on the table, it is SELECT (shared) locks (when SELECT tries to read multiple rows) are escalated to a table lock and cannot be granted because table has already exclusive (UPDATE) lock.

And presence or absence of index was unrelated to my primary question

I shift the discussion of this topic to my submitted suggestion "Intent rowlocks should not be escalated to a table lock if a table already contains exclusive lock"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文