Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 更新表时避免死锁_Sql_Sql Server_Database Deadlocks - Fatal编程技术网

Sql 更新表时避免死锁

Sql 更新表时避免死锁,sql,sql-server,database-deadlocks,Sql,Sql Server,Database Deadlocks,我有一个三层应用程序,在客户端缓存数据,所以我需要知道服务器上的数据何时更改,以保持此缓存同步 因此,我在表中添加了一个“lastmodification”字段,并在数据更改时更新该字段。但如果子行(使用FK)被修改,则必须更新某些“父”lastmodification行。 从主表中获取MAX(lastmodification),从相关表中获取MAX,然后这几个值中的MAX开始工作,但有点慢。 我的意思是: 因此,我切换并向该表添加了一个触发器,以便它更新TBL_元数据表中的一个字段: CREA

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

因此,我在表中添加了一个“lastmodification”字段,并在数据更改时更新该字段。但如果子行(使用FK)被修改,则必须更新某些“父”lastmodification行。
从主表中获取MAX(lastmodification),从相关表中获取MAX,然后这几个值中的MAX开始工作,但有点慢。 我的意思是:

因此,我切换并向该表添加了一个触发器,以便它更新TBL_元数据表中的一个字段:

CREATE TABLE [TABLE_METADATA](
    [TABLE_NAME] [nvarchar](250) NOT NULL,
    [TABLE_LAST_MODIFICATION] [datetime] NOT NULL
现在,相关表只需更新元数据表中的上次修改,即可更新“main”表的上次修改时间。 获取上次修改现在很快

但是。。。现在,我已经了解了与更新此表相关的随机死锁

这是由于两个事务在不同的步骤修改表_元数据,然后相互锁定

我的问题:您是否看到一种在不锁定行的情况下保持此上次修改更新的方法? 就我而言,我真的不在乎:

  • 即使事务回滚,lastmodification也会保持更新
  • “脏”上次修改(已更新但尚未提交)已被删除 被新值覆盖
事实上,我真的不需要这些更新出现在事务中,但是当它们被触发器执行时,它会自动出现在当前事务中


谢谢您的帮助

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

您还可以对连接到正在更新的表的表使用
和(nolock)
。另一种方法是使用
设置事务隔离级别readuncommitted
。 但使用此方法时要小心,因为可能会创建损坏的数据

例如:

update mt with (rowlock)
    set SomeColumn = Something
    from MyTable mt
        inner join AnotherTable at with (nolock)
        on mt.mtId = at.atId
您还可以将
与(rowlock)
与(nolock)
/
设置事务隔离级别read uncommitted
添加到经常读写同一表的其他数据库对象,以进一步降低死锁发生的可能性

如果死锁仍在发生,您可以通过如下方式自连接来减少目标表上的读锁定:

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

可以找到更多关于表提示的文档

您是否尝试过使用NOLOCK hint之类的工具?这将在不使用任何锁的情况下更新,因此不应导致死锁我知道select的NOLOCK提示,但不知道更新时可以使用它?我会查一查的,谢谢你不用担心,我忘了这是只供选择的。。。尝试一下,您会得到:“对于INSERT、UPDATE、DELETE或MERGE语句的目标表,不允许使用NOLOCK和READUNCOMMITED锁定提示。”这是一个非常有趣的答案。我从来没有看到过这样的建议,即更新速度会更快(涉及大量共享锁和独占锁),如果与未提交读取结合使用,则锁会更少。在执行更新时,您确实希望确保您正在更新“正确”的行。结合nolock(这是一种未提交的读取,意味着您可能正在使用永远不会提交的更改)可能会导致一些非常有趣的损坏数据。您有一个很好的观点,我没有提到这一点,因为OP说他们并不真正关心“脏”更新/读取。关于这一点,我将增加一小部分。我们不应该仅仅因为用户说他们不在乎而鼓励不良行为。很少有情况下read uncommitted是合适的。@JoshB问题是我不关心它,只关心lastmodification值。但是更改事务级别不仅会影响lastmodification查询,还会影响此事务中执行的所有查询,实际上,在这种情况下,我会遇到一致性问题,所以我不能这样做。我将阅读有关rowlock提示的文档。
update mt with (rowlock)
    set SomeColumn = Something
    from MyTable mt
    where mt.Id in (select Id from MyTable mt2 where Column = Condition)