【问题标题】:Snapshot isolation transaction aborted due to update conflict由于更新冲突,快照隔离事务中止
【发布时间】:2012-05-23 11:05:20
【问题描述】:

以下声明:

INSERT INTO dbo.Changes([Content], [Date], [UserId], [CompanyId]) 
  VALUES (@1, @2, @3, @4);
SELECT @@identity;

给我这个 SQL 错误 3960:

快照隔离事务由于更新冲突而中止。你 无法使用快照隔离直接访问表 'dbo.Companies' 或间接在数据库“myDatabase”中更新、删除或插入 已被另一个事务修改或删除的行。 重试事务或更改隔离级别 更新/删除语句。

据我了解,根据错误消息,在另一个连接正在修改dbo.Companies 期间,我不应该更新、删除或插入表dbo.Companies

但是为什么当我向另一个表dbo.Changes(具有dbo.Companies 的外键)插入新行并且我没有删除dbo.Companies 中的引用行时会发生这种情况,但我只是在更新行dbo.Companies 而不是主键?这应该可以正常工作,不是吗? (这是 SQL Server 中的错误吗?)

更新:

表格如下所示:

dbo.Changes([Id] int PK, [Content] nvarchar, 
  [Date] datetime, [UserId] int, [CompanyId] int -> dbo.Companies.[Id])
dbo.Companies([Id] int PK, [Name] nvarchar)

第二次更新在做:

UPDATE dbo.Companies WHERE [Id] = @1 SET [Name] = @2;

【问题讨论】:

    标签: sql-server tsql transactions transaction-isolation snapshot-isolation


    【解决方案1】:

    似乎 SQL Server 将在它必须读取的任何记录上获得更新锁即使它没有修改它

    更多信息microsoft.public.sqlserver.server thread:

    没有关于 CustomerContactPerson 的支持索引,声明

    从联系人中删除 ID = @ID;

    需要一个“电流” 读取 CustomerContactPerson 中的所有行以确保存在 没有引用已删除的 CustomerContactPerson 行 联系人行。使用索引,DELETE 可以确定 没有阅读 CustomerContactPerson 中没有相关的行 受其他事务影响的行。

    另外,在快照中 交易你要转向的读取数据的模式 周围和更新是在阅读时采取UPDLOCK。这确保 您正在根据“当前”数据进行更新,而不是 “一致”(快照)数据,并且当您发布 DML 时,它 数据不会被锁定,并且您不会无意中覆盖另一个 会话的变化。

    我们的解决方法是向外键添加索引

    在您的示例中,我怀疑向 Changes.CompanyId 添加索引会有所帮助。我不确定这是否是一个真正的解决方案。 SQL Server 优化器可以选择不使用索引吗?

    【讨论】:

    • 感谢您的提示,但似乎没有帮助。
    • 两个语句(INSERT 和 UPDATE)是否指向同一个客户?如果是这样,据我所知,我们很不走运。
    • 是的,insert 正在使用当前更新公司的 id。
    • 通读(长)dbaspot线程,听起来这是SQL Server的限制。此答案中的索引仅在两个陈述涉及不同客户的情况下才有帮助。
    • 谢谢,碰巧有一个表有十几个 FK,没人关心创建索引,在创建缺少的索引后,到目前为止没有出现类似的错误。
    【解决方案2】:

    SQL Server 可以看到对依赖表的更新,这可能会修改插入的行为......对我来说似乎很公平,因为 SQL 无法猜测其他逻辑可能依赖于 [name] 列(触发器等)

    如果您的应用程序实现了死锁重试逻辑,您可以修改它们以将错误号 3960 与错误号 1205 相同并自动重试...

    【讨论】:

    • 你说得很好......除了,我仍然不明白为什么在相关表的外键列上有一个非聚集、非唯一索引就足以让这种情况不会发生——即即使使用索引,它仍然可以修改插入的行为吗?
    • @Kram 我想索引有助于粒度。引擎知道需要锁定依赖表,但如果没有索引,它可以尝试锁定整个表而不是单行
    猜你喜欢
    • 1970-01-01
    • 2011-07-03
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多