为什么 UPDATE 会在不相关的行上阻止 SELECT?
有了脚本 [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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我相信这是因为你没有主键,我认为这会导致锁升级,从而阻止 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.
后重复测试
在SELECT 2) 仍然被阻止
SELECT 2) 不会被阻止
如果将 2) 修改为如下
所示,即使没有任何索引或 PK,2b) 也不会被阻止。
不过,2b),没有任何索引,在修改 1) UPDATE 以在可序列化下运行后被阻止
但不是在 REPEATABLE READ 或更低的情况下
所以,看起来多行选择尝试获取不可共享锁?
更新:
好吧,在所有 SELECT 被阻塞的情况下,它都会等待获取 LCK_M_IS
了解这道美食的充分理由
更新2:
嗯,这不是在表上升级的 UPDATE 锁,而是 SELECT(共享)锁(当 SELECT 尝试读取多行时)升级为表锁并且无法授予,因为表已经具有独占(UPDATE) )锁定。
并且索引的存在或不存在与我的主要问题无关
我将这个主题的讨论转移到我提交的建议"不应升级意图行锁如果表已包含排它锁,则为表锁”
Repeating tests after
SELECT 2) is still blocked
SELECT 2) is NOT blocked
If to modify 2) as
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
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"