【问题标题】:SQL Server - confusion about serializable isolation levelSQL Server - 关于可序列化隔离级别的混淆
【发布时间】:2017-10-20 11:05:41
【问题描述】:

我已阅读文章 (https://www.simple-talk.com/sql/t-sql-programming/questions-about-t-sql-transaction-isolation-levels-you-were-too-shy-to-ask/),我有一个问题,根据:

"SERIALIZABLE:当前事务中的查询不能读取另一个尚未提交的事务修改的数据。在当前事务完成之前,没有其他事务可以修改当前事务正在读取的数据,并且没有其他事务可以插入新的行将匹配当前事务中的搜索条件,直到完成。因此,Serializable 隔离级别可以防止脏读、不可重复读和幻读。但是,与其他隔离级别相比,它对性能的影响最大。 "

我对从 1 个会话/查询插入不满足搜索条件的新行感到困惑。示例如下:

假设我有桌子

EmpID   FirstName
1       john
2       new employee
3       A new employee

并在单独的选项卡中查询:

--session 1----------------------------------
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

    SELECT FirstName FROM EmployeeInfo
    WHERE FirstName like 'new empl%'

    WAITFOR DELAY '00:00:10'  

    SELECT FirstName FROM EmployeeInfo
    WHERE FirstName like 'new empl%'

ROLLBACK TRANSACTION;

---------session 2---------------------------
begin transaction;

    UPDATE EmployeeInfo
    SET FirstName = 'frank'
    WHERE EmpID = 1;

commit transaction;

-----session 3----
insert into EmployeeInfo values('A new employe 2')

我一个接一个地执行查询:会话 1、会话 2、会话 3。 我预计会话 1 不会停止会话 2 和会话 3 的执行,因为来自该会话的更新和插入不满足第一个查询中使用的搜索条件。但是,在结果中,我可以看到会话 1 必须在会话 2 和会话 3 执行之前完成(回滚)。

但是,虽然我在会话 1 中使用其他搜索条件,如下所示:

--session 1
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

SELECT EmpID, FirstName FROM EmployeeInfo
WHERE EmpID = 2

WAITFOR DELAY '00:00:10'  

SELECT FirstName FROM EmployeeInfo

ROLLBACK TRANSACTION;

然后,会话 2 和会话 3 独立于会话 1 完成。 这是为什么?为什么喜欢条件块插入而“=”不插入?

编辑: 1. EmpID 上只有一个主键。

【问题讨论】:

  • 包含索引的表的定义是什么?

标签: sql-server database isolation-level


【解决方案1】:

这是因为“在完成之前,没有其他事务可以插入与当前事务中的搜索条件匹配的新行”。 SQL Server 通过采用范围锁来防止插入冲突来强制执行此操作。

如果您在 EmployeeInfo.FirstName 上有一个索引,SQL 可能会采用窄锁来强制执行此操作。但是如果没有索引,SQL 会使用一个锁来阻止任何插入。此外,如果索引不支持 SELECT 查询谓词,它将阻止所有插入。

您可以通过以下方式检查锁的当前状态:

select @@spid this_session, *
from sys.dm_tran_locks

。请注意,这种行为使 SERIALIZABLE 成为一个不太有用的隔离级别。而且您真的应该只使用 READ COMMITTED 和 SNAPSHOT,可能会为特定事务添加锁定提示。

【讨论】:

  • 能否请您扩展您的断言,即这种行为使serializable 不是很有用?我发现它是一个非常有用的隔离级别,我想更多地了解导致您得出相反结论的原因。
  • 这个案例确实是一个案例。由于不那么明显的原因,一个简单的 SELECT 查询会阻止对整个表的插入。因此,它往往会大大降低应用程序中的并发性。这样做的一个令人讨厌的副作用是它为死锁创造了很多机会。而且它没有太大的好处,因为它保证的隔离行为不是很有用。
  • 听起来更像是在说它作为 default 隔离级别不是很有用。你是这个意思吗?
  • 我真的不喜欢更改隔离级别根本。我认为在 READ COMMITTED 事务中根据需要对单个查询使用锁定提示更简单、更有效。
  • 我想我现在明白你的意思了。所以你说serializable 在使用set transaction isolation level serializable 作为连接级别设置或在过程中不是非常有用的隔离级别,而不是仅使用with (serializable) 之类的提示。对吗?
猜你喜欢
  • 2021-06-21
  • 1970-01-01
  • 2019-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-16
  • 2015-03-24
相关资源
最近更新 更多