更新表时避免死锁

时间:2017-05-18 10:32:25

标签: sql sql-server database-deadlocks

我有一个3层应用程序并在客户端缓存数据,所以我需要知道服务器上的数据何时更改以保持此缓存同步。

所以我添加了一个" lastmodification"表中的字段,并在数据更改时更新此字段。但是一些父母的父母'如果修改子行(使用FK),则必须更新lastmodification行 从主表中获取MAX(lastmodification),从相关表中获取MAX,然后从这几个值中获取MAX,但是有点慢。 我的意思是:

MAX(MAX(MAIN_TABLE), MAX(CHILD1_TABLE), MAX(CHILD2_TABLE))

所以我切换并在此表中添加了一个触发器,以便更新TBL_METADATA表中的字段:

CREATE TABLE [TABLE_METADATA](
    [TABLE_NAME] [nvarchar](250) NOT NULL,
    [TABLE_LAST_MODIFICATION] [datetime] NOT NULL

现在相关的表格可以更新“主要内容”。通过更新元数据表中的最后一个修改来表最后修改时间。 现在快速获取lastmodification

但是......现在我有与更新此表相关的随机死锁。

这是由于2个事务在不同步骤修改TABLE_METADATA,然后相互锁定。

我的问题:你是否看到了一种方法来保持这种最后修改更新而不锁定行? 就我而言,我真的不在乎:

  • 即使交易是回滚,也会更新lastmodification保持更新
  • '脏' lastmodification(更新但尚未提交)是 被新值覆盖

事实上,我真的不需要将这些更新放在交易中,但是当它们被触发器执行时,它会在当前交易中自动执行。

感谢您的帮助

1 个答案:

答案 0 :(得分:1)

据我所知,你无法阻止U型锁。但是,您可以尝试使用with (rowlock)将锁的数量减少到最少。 这将告诉查询优化器在更新行时逐个锁定行,而不是使用页面或表锁。

您还可以对连接到正在更新的表的表使用with (nolock)。另一种方法是使用set transaction isolation level read uncommitted。 但是请小心使用此方法,因为您可能会创建损坏的数据。

例如:

update mt with (rowlock)
    set SomeColumn = Something
    from MyTable mt
        inner join AnotherTable at with (nolock)
        on mt.mtId = at.atId

您还可以将with (rowlock)with (nolock) / set transaction isolation level read uncommitted添加到经常读写相同表的其他数据库对象,以进一步降低发生死锁的可能性。

如果仍然发生死锁,您可以通过自联接减少目标表上的读锁定,如下所示:

update mt with (rowlock)
    set SomeColumn = Something
    from MyTable mt
    where mt.Id in (select Id from MyTable mt2 where Column = Condition)

可以找到有关表提示的更多文档here.

相关问题