【问题标题】:Read committed Snapshot VS Snapshot Isolation Level读取提交的快照 VS 快照隔离级别
【发布时间】:2011-02-14 00:33:09
【问题描述】:

请有人帮助我了解何时在 SQL Server 中使用 SNAPSHOT 隔离级别而不是 READ COMMITTED SNAPSHOT?

我知道在大多数情况下 READ COMMITTED SNAPSHOT 有效,但不确定何时进行 SNAPSHOT 隔离。

谢谢

【问题讨论】:

    标签: sql-server snapshot isolation-level read-committed-snapshot


    【解决方案1】:

    READ COMMITTED SNAPSHOT 进行乐观读取和悲观写入。相比之下,SNAPSHOT 进行乐观读取和乐观写入。

    对于大多数需要行版本控制的应用,Microsoft 建议使用 READ COMMITTED SNAPSHOT

    阅读这篇出色的 Microsoft 文章:Choosing Row Versioning-based Isolation Levels。它解释了两种隔离级别的好处和成本。

    这里有一个更彻底的: http://msdn.microsoft.com/en-us/library/ms345124(SQL.90).aspx

    【讨论】:

    • 这似乎不正确。见dba.stackexchange.com/a/54681/52708
    • 乐观读和乐观写有什么区别?谷歌搜索不解释,谢谢,
    • 这是一个术语还不明白的答案,甚至没有人知道乐观读、乐观写、悲观读、悲观写的含义,
    • 乐观和悲观是相当常见的术语,它们确实有意义。我看不出发布的链接与这个答案有何矛盾。
    【解决方案2】:

    [![隔离级别表][2]][2]

    请看下面的例子:

    读取提交的快照

    如下更改数据库属性

    ALTER DATABASE SQLAuthority
    SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE
    GO
    

    会话 1

    USE SQLAuthority
    GO
    BEGIN TRAN
    UPDATE DemoTable
    SET i = 4
    WHERE i = 1
    

    第 2 场

    USE SQLAuthority
    GO
    BEGIN TRAN
    SELECT *
    FROM   DemoTable
    WHERE i = 1
    

    结果 – 会话 2 中的查询显示旧值 (1, ONE),因为当前事务未提交。这也是避免阻塞和读取已提交数据的方法。

    会话 1

    COMMIT
    

    第 2 场

    USE SQLAuthority
    GO
    SELECT *
    FROM   DemoTable
    WHERE i = 1
    

    结果 - 会话 2 中的查询不显示任何行,因为行在会话 1 中更新。因此,我们再次看到已提交的数据。

    快照隔离级别

    这是新的隔离级别,从 SQL Server 2005 开始提供。对于此功能,应用程序需要进行更改,因为它必须使用新的隔离级别。

    使用以下更改数据库设置。我们需要确保数据库中没有事务。

    ALTER DATABASE SQLAuthority SET AllOW_SNAPSHOT_ISOLATION ON
    

    现在,我们还需要使用下面的方法来改变连接的隔离级别

    会话 1

    USE SQLAuthority
    GO
    BEGIN TRAN
    UPDATE DemoTable
    SET i = 10
    WHERE i = 2
    

    第 2 场

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT
    GO
    USE SQLAuthority
    GO
    BEGIN TRAN
    SELECT *
    FROM   DemoTable
    WHERE i = 2
    

    结果 - 即使我们将值更改为 10,我们仍然会在会话 2 (2, TWO) 中看到旧记录。

    现在,让我们在会话 1 中提交事务

    会话 1

    COMMIT
    

    让我们回到会话 2 并再次运行 select。

    第 2 场

    SELECT *
    FROM   DemoTable
    WHERE i = 2
    

    我们仍然会看到记录,因为会话 2 已经声明了具有快照隔离的事务。除非我们完成交易,否则我们不会看到最新记录。

    第 2 场

    COMMIT
    SELECT *
    FROM   DemoTable
    WHERE i = 2
    

    现在,我们应该看不到该行,因为它已经更新了。

    见:SQL AuthoritySafari Books Online

    【讨论】:

    • 这个答案的例子比选择的答案好得多。
    • 同意,这是指向外部资源的最佳答案。
    【解决方案3】:

    如果不讨论快照中可能发生的可怕的“快照更新冲突”异常,快照和已提交快照读取的比较是不完整的,但快照已提交读取除外。

    简而言之,快照隔离在事务开始时检索已提交数据的快照,然后对读取和写入使用乐观锁定。如果在尝试提交事务时,发现其他东西更改了相同的数据,则数据库将回滚整个事务并引发错误,从而导致调用代码中的快照更新冲突异常。这是因为受事务影响的数据版本在事务结束时与开始时不同。

    Snapshot Read Committed 不会遇到这个问题,因为它使用写入锁定(悲观写入)并且它在每个语句的状态 处获取所有已提交数据的快照版本信息。

    Snapshot 和 NOT Snapshot Read Committed 发生快照更新冲突的可能性是两者之间极其显着的区别。

    【讨论】:

      【解决方案4】:

      仍然相关,从 Bill 的 cmets 开始,我阅读了更多内容,并做了一些可能对其他人有用的笔记。

      默认情况下,单个语句(包括 SELECT)对“已提交”数据(READ COMMITTED)起作用,问题是:它们是否等待数据“空闲”并在读取时阻止其他语句工作?

      通过右键单击数据库“属性 -> 选项 -> 杂项”进行设置:

      并发/阻塞:读取提交快照是否开启 [默认关闭,应该开启]:

      • 使用 SNAPSHOT 进行选择(读取),不要等待其他人,也不要阻止他们。
      • 无需更改代码即可实现效果操作
      • ALTER DATABASE <dbName> SET READ_COMMITTED_SNAPSHOT [ON|OFF]
      • SELECT name, is_read_committed_snapshot_on FROM sys.databases

      一致性:允许快照隔离 [默认关闭,有争议 – OK 关闭]:

      • 允许客户端跨 SQL 语句(事务)请求 SNAPSHOT。
      • 代码必须请求“事务”快照(如SET TRANSACTION ...
      • ALTER DATABASE <dbName> SET ALLOW_SNAPSHOT_ISOLATION [ON|OFF]
      • SELECT name, snapshot_isolation_state FROM sys.databases

      问题是:Read Committed Snapshot 和 Allow Snapshot Isolation 之间不是一个。它们是 Snapshot 的两种情况,可以独立打开或关闭,其中 Allow Snapshot Isolation 是一个高级主题。允许快照隔离允许代码进一步控制快照领域。

      如果您考虑一行,问题似乎很清楚:默认情况下,系统没有副本,因此如果其他人正在写入,读取器必须等待,如果其他人正在读取,写入器也必须等待 - 该行必须一直锁定。启用“Is Read Committed Snapshot On”会激活数据库以支持“快照副本”以避免这些锁定。

      漫无目的...

      在我看来,“Is Read Committed Snapshot On”对于任何普通的 MS SQLServer 数据库都应该是 TRUE,并且默认情况下它提供 FALSE 是一种过早的优化。

      但是,有人告诉我,单行锁变得更糟,不仅因为您可能要跨表处理多行,还因为在 SQL Server 中,行锁是使用“块”级锁实现的(锁定与存储接近相关的随机行) 并且存在多个锁触发表锁定的阈值 - 可能是更“乐观”的性能优化,但有可能在繁忙的数据库中出现阻塞问题。

      【讨论】:

        猜你喜欢
        • 2014-01-03
        • 1970-01-01
        • 2021-01-27
        • 2020-01-08
        • 2010-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多