AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 58001
Accepted
Ian Boyd
Ian Boyd
Asked: 2014-02-01 08:08:27 +0800 CST2014-02-01 08:08:27 +0800 CST 2014-02-01 08:08:27 +0800 CST

在 READ COMMITTED 隔离中,更新后是否可以读取旧值?

  • 772

我正在尝试解决 SQL Server 2008 R2 的问题并且正在抓紧救命稻草。

鉴于数据位于 B 树的叶节点中,并且也存在于索引中,有人可以在单个UPDATE语句中读取多个值吗?

想象一个进程更新一行:

--Change status from Pending -> Waiting
BEGIN TRANSACTION
   UPDATE Transactions SET Status = 'Waiting'
   WHERE TransactionID = 12345
COMMIT TRANSACTION

是否有可能在此期间BEGIN TRANS; UPDATE; COMMIT另一个进程可以读取新值和旧值?

我想知道这一点,因为更新不会仅在一个地方更改值。该值将存在于多个地方:

  • 聚集索引的叶节点
  • IX_Transactions_1
  • IX_Transactions_2
  • IX_Transactions_3
  • IX_Transctions_4
  • IX_Transctions_5
  • ...
  • IX_Transactions_n

如果更新开始,它必须更新所有这些位置的值。如果另一个进程使用索引执行计划来查找值会发生什么:

  • IX_Clustered:等待中
  • IX_Transactions_1:等待中
  • IX_Transactions_2:等待中
  • IX_Transactions_3:待定
  • IX_Transactions_4:待定
  • IX_Transactions_5:待定
  • ...
  • IX_Transactions_n:待定

在那一刻,如果发出一个查看聚集索引中的值的查询,它将找到Waiting。

但是,如果查询使用IX_Transactions_4它,它将找到一个值Pending。

取消记录锁定机制

内部的锁定顺序没有记录,但我假设 SQL Server 在聚集和非聚集索引上采用共享锁:

  • IX_Clustered:共享
  • IX_Transactions_1:共享
  • IX_Transactions_2:共享
  • IX_Transactions_3:共享
  • IX_Transactions_4:共享
  • IX_Transactions_5:共享

然后将这些锁升级为更新锁:

  • IX_Clustered:共享更新
  • IX_Transactions_1:共享更新
  • IX_Transactions_2:共享更新
  • IX_Transactions_3:共享更新
  • IX_Transactions_4:共享更新
  • IX_Transactions_5:共享更新

此时,另一个进程仍然可以读取这 5 个索引中的值;因为选择与更新锁兼容。

然后更新继续。如果我们及时拍一张照片:

  • IX_Clustered:共享 更新独占 -> 值已更改
  • IX_Transactions_1:共享 更新独占 -> 值已更改
  • IX_Transactions_2:共享 更新独占
  • IX_Transactions_3:共享更新
  • IX_Transactions_4:共享更新
  • IX_Transactions_5:共享更新

另一个进程不能再从具有排他锁的项目中读取值,但它仍然可以从仍然具有更新锁的项目中读取值(共享锁与更新锁兼容)

当然除非那不是发生的事情

这仅在 SQL 仅根据需要提升为独占时才有效。相反,如果它是这样的:

  • IX_Clustered:S U IX X -> 值已更改
  • IX_Transactions_1:S U IX X -> 值已更改
  • IX_Transactions_2:S U IX X
  • IX_Transactions_3:S U IX
  • IX_Transactions_4:S U IX
  • IX_Transactions_5:S U IX

我不能再打字了;我继续下去的意志被粉碎了。就像我说的,我正在抓住救命稻草。

sql-server-2008-r2
  • 1 1 个回答
  • 231 Views

1 个回答

  • Voted
  1. Best Answer
    Martin Smith
    2014-02-01T10:19:57+08:002014-02-01T10:19:57+08:00

    您可以使用跟踪标志1200打印出锁定信息和3916日志记录信息。(均为无证 AFAIK)

    对于以下测试设置

    CREATE TABLE T
    (
    A INT IDENTITY PRIMARY KEY,
    B INT
    )
    
    CREATE NONCLUSTERED INDEX IX ON T(B)
    
    INSERT INTO T 
    SELECT number
    FROM master..spt_values
    

    然后运行以下两次(因为第二次运行不包含编译期间获得的无关锁)

    DBCC TRACEON(3604,1200,3916,-1) WITH NO_INFOMSGS
    
    SET NOCOUNT ON;
    
    UPDATE T 
    SET B += 1
    WHERE A = 1000
    
    /*If you habitually have 3604 on then change the below*/
    DBCC TRACEOFF(3604,1200,3916,-1) WITH NO_INFOMSGS
    

    这将返回以下输出

    进程 54 获取对象上的 IX 锁:11:245575913:0(类 bit2000000 ref1)结果:OK

    进程 54 获取 PAGE 上的 IU 锁:11:1:127(class bit0 ref1)结果:OK

    进程 54 获取 KEY 上的 U 锁:11:72057594039042048 (1f00de11a529) (class bit0 ref1) 结果:OK

    进程 54 在 PAGE 上获取 IX 锁:11:1:127(类 bit2000000 ref0)结果:OK

    进程 54 获取 KEY 上的 X 锁:11:72057594039042048 (1f00de11a529) (class bit2000000 ref0) 结果:OK

    XdesId 0000:00000423: m_logReserved 9162,delta 9162,操作 LOP_BEGIN_XACT,调用方 GenerateLogRec,LSN 00000027:00000159:0001。

    XdesId 0000:00000423: m_logReserved 9379, delta 217, op LOP_MODIFY_ROW, caller GenerateLogRec, LSN 00000027:00000159:0002。

    进程 54 在 PAGE 上获取 IX 锁:11:1:166(类 bit2000000 ref1)结果:OK

    进程 54 获取 KEY 上的 X 锁:11:72057594039107584 (dbf572a551f4) (class bit2000000 ref1) 结果:OK

    XdesId 0000:00000423: m_logReserved 9597,delta 218,操作 LOP_DELETE_ROWS,调用者 GenerateLogRec,LSN 00000027:00000159:0003。

    进程 54 在 PAGE 上获取 IX 锁:11:1:166(类 bit2000000 ref0)结果:OK

    进程 54 获取 KEY 上的 RangeI-N 锁:11:72057594039107584 (a39688da7d04) (class bit1000000 ref1) 结果:OK

    进程 54 获取 KEY 上的 X 锁:11:72057594039107584 (82cbfa4b30c1) (class bit2000000 ref0) 结果:OK

    XdesId 0000:00000423: m_logReserved 9671,delta 74,操作 LOP_INSERT_ROWS,调用者 GenerateLogRec,LSN 00000027:00000159:0004。

    进程 54 释放 KEY 上的锁定引用:11:72057594039107584 (dbf572a551f4)

    进程 54 释放 PAGE 上的锁定引用:11:1:166

    进程 54 释放 KEY 上的锁定引用:11:72057594039042048 (1f00de11a529)

    进程 54 释放 PAGE 上的锁定引用:11:1:127

    XdesId 0000:00000423: m_logReserved 0, delta -9671, op LOP_COMMIT_XACT, caller GenerateLogRec, LSN 00000027:00000159:0005。

    在更新聚集索引键(在页面上1:166)之前,不会对非聚集索引 () 采取任何锁定,所以是的,这是可能的。LOP_MODIFY_ROW1:127

    以上是一个狭窄的(每行)更新计划。

    对于宽(每个索引)计划,每个索引都会依次更新。可能按照下面的计划进行干预排序操作。

    在此处输入图像描述

    这将使机会窗口变宽,但是,虽然事务可能会从尚未更新的索引中读取“旧”值,但读取已提交的事务不可能读取值的“新”版本,直到事务已提交。

    读取已提交的语句当然有可能读取相同值的两个不同的已提交版本。

    在一次连接运行中

    WHILE ( 1 = 1 )
      BEGIN
          UPDATE T
          SET    B += 1
          WHERE  A = 1000;
      END 
    

    然后在另一场比赛中

    SELECT *
    FROM   T T1 WITH(READCOMMITTEDLOCK )
           INNER HASH JOIN T T2  WITH(READCOMMITTEDLOCK )
             ON T1.A + 0 = T2.A + 0
    WHERE  T1.A = 1000
           AND T2.A = 1000
    

    对我来说,大约有 50% 的时间第二次查询返回具有不同B值的行,因为值在两次搜索之间发生变化T。

    • 6

相关问题

  • SQL Server 2008 R2 中的自动收缩、加密和恢复模型属性

  • SQL Server 2008 R2 群集的无人参与安装失败并出现错误 - “路径中有非法字符”。

  • 迁移大型数据库

  • 代理执行的维护计划

  • 随机化表内容并将它们存储回表中

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve