4

我有许多通过我的应用程序更新的表,它们返回大量数据或难以查询更改。为了解决这个问题,我创建了一个带有单行的“LastUpdated”表,并在这些复杂表上设置了一个触发器,它只针对 LastUpdated 表中的相应列设置 GetDate():

CREATE TRIGGER [dbo].[trg_ListItem_LastUpdated] ON [dbo].[tblListItem] 
FOR INSERT, UPDATE, DELETE 
AS
UPDATE LastUpdated SET ListItems = GetDate()
GO

这样,客户端只需查询该表的最后更新值,然后就可以决定是否需要从复杂表中刷新数据。复杂表使用快照隔离来防止脏读。

在繁忙的系统中,由于“LastUpdated”中的更新冲突,我们每天大约会遇到一次在复杂表中写入或更新数据的错误。因为这发生在触发器执行的语句中,所以受影响的复杂表无法保存数据。记录以下错误:

由于更新冲突,快照隔离事务中止。您不能使用快照隔离直接或间接访问数据库“devDB”中的表“dbo.tblLastUpdated”来更新、删除或插入已被另一个事务修改或删除的行。重试事务或更改更新/删除语句的隔离级别。

我应该在触发器中做什么来防止这种失败?我可以在触发器上使用某种查询提示来避免这种情况 - 还是我可以忽略触发器中的错误?更新 LastUpdated 中的数据并不重要,但将数据正确保存到复杂表中才是关键。

这可能是我忽略或不知道的非常简单的事情。一如既往,感谢您提供任何信息。

4

4 回答 4

3

我想说你应该考虑使用Change Trackinghttp://msdn.microsoft.com/en-gb/library/cc280462%28v=sql.100%29.aspx),这是你可以使用的轻量级内置 SQL Server 功能监视表已更改的事实,而不是记录每个单独的更改(您也可以使用Change Data Capture)。它需要您已经在使用的快照隔离。

因为您的触发器正在您的父事务中运行,并且您的快照已过期,所以您的整个事务需要重新开始。如果这是一个复杂的工作负载,那么以这种方式维护最后更新的数据将会很昂贵。

于 2013-04-24T13:14:50.870 回答
1

简短的回答 - 不要那样做!使更新的事务依赖于单个共享行使其容易出现死锁和更新冲突,整个范围都是令人讨厌的事情。

您可以使用视图来确定上次更新,例如:

SELECT
    t.name
    ,user_seeks
    ,user_scans
    ,user_lookups
    ,user_updates
    ,last_user_seek
    ,last_user_scan
    ,last_user_lookup
    ,last_user_update
FROM sys.dm_db_index_usage_stats i JOIN sys.tables t 
    ON (t.object_id = i.object_id)
WHERE database_id = db_id()

或者,如果您真的坚持使用LastUpdate的解决方案,您可以在自治事务中从触发器实现它的更新。即使 SQL Server 不支持自治事务,它也可以使用喜欢的服务器来完成:如何在 SQL Server 2008 中创建自治事务

于 2013-04-24T05:22:16.897 回答
1

架构需要改变。如果您必须保留更新表,请为每个表创建一行。这将大大减少您的锁,因为每个表都可以更新自己的行,而不是竞争表中的唯一行。

最近更新时间

table_name (varchar(whatever)) pk
modified_date (datetime)

新触发器tblListItem

CREATE TRIGGER [dbo].[trg_ListItem_LastUpdated] ON [dbo].[tblListItem] 
FOR INSERT, UPDATE, DELETE 
AS
UPDATE LastUpdated SET modified_date = GetDate() WHERE table_name = 'tblListItem'
GO

我经常使用的另一个选项是在每个表中都有一个 modified_date 列。然后人们确切地知道要更新/插入哪些记录以与您的数据同步,而不是在每次更改或插入一条记录时删除和重新加载表中的所有内容。

于 2013-04-24T13:33:36.333 回答
0

或者,您可以在用于更新应用程序中的复杂表的同一事务中更新日志表,并完全避免触发。

更新 您还可以选择插入新行而不是更新LastUpdated表中的同一行。然后,您可以查询最大时间戳以获取最新更新。但是,使用这种方法,您的LastUpdated表每天都会增长,如果交易量很高,您需要注意这一点。

于 2013-04-24T05:53:49.317 回答