【问题标题】:T-SQL: Trigger that runs right before the end of a modifying transactionT-SQL:在修改事务结束之前运行的触发器
【发布时间】:2015-08-03 09:07:20
【问题描述】:

问题陈述

我有一个从 3 个不同的大表到​​超大表递归收集和聚合信息的视图。此视图本身需要相当长的时间来执行,但在许多 select 语句中都需要并且经常执行。

但是,生成的视图非常小(2 列中有几十个结果)。

所有更新操作通常会启动一个事务,执行数千个 INSERT,然后提交该事务。这种情况不会经常发生,但如果将某些内容写入数据库,则通常是大量数据。

我尝试了什么

  1. 由于视图很小,不经常变化,经常阅读,我想到了创建一个索引视图。但是,遗憾的是,您无法使用 CTE 甚至递归 CTE 创建索引视图。
  2. 为了“模拟”索引或物化视图,我考虑编写一个触发器,该触发器在每次修改一个基表时执行视图并将结果存储到一个表中。但是,我想如果大量条目被更新或插入并且触发器针对这些表上的每个 INSERT/UPDATE 语句运行,即使它们在单个事务中,这将永远需要。

实际问题

是否可以编写一个触发器,该触发器在提交之前和事务的最后一个插入/更新语句完成之后运行一次,并且仅当任何语句更改了三个表中的任何一个时才运行?

【问题讨论】:

  • 直接,不,触发器每个触发语句运行一次。间接地,您可以将所有 INSERT 插入到临时表中,然后将它们一起从 #temp 表插入到真实表中,从而为该表触发一个触发器。但是,如果您要写入多个表,您仍然会遇到同样的问题。解决此问题的 SOP 方法是让存储过程在前面处理所有内容,而不是让 Trigger 试图在后端捕获所有内容。
  • 修改基表时,是使用单个 INSERT 或 UPDATE 语句影响多行还是使用了许多粒度语句?
  • 好吧,您可以编写触发器来记录每个表中的每次数据更改。然后编写一个作业,每隔几分钟左右检查一次任何更改,并相应地使用您的视图更新表。这样它就不会触发太多次,但您的数据在一定时间内是最新的。
  • @Ben Gribaudo:有很多细粒度的语句,即将几千条记录作为一个“批处理”事务插入到一张表中。
  • @Stephan:感谢您的想法,但在此应用程序中,数据一致性至关重要。数据必须始终保持一致,因此与每个事务的提交一致。不幸的是,这里不可能采用“最终一致”的方法。

标签: sql sql-server sql-server-2008 tsql triggers


【解决方案1】:

不,没有直接的方法可以使触发器在事务结束之前运行。每个触发 DML 语句(INSERTUPDATEDELETE)运行一次 DML 触发器,并且没有其他类型的与数据修改相关的触发器。

间接地,您可以将所有 INSERT 插入到临时表中,然后将它们一起从 #temp 表插入到真实表中,从而为该表触发一个触发器。但是,如果您要写入多个表,您仍然会遇到同样的问题。

解决此问题的 SOP(标准操作实践)方法是让存储过程在前面处理所有内容,而不是让触发器尝试在后端捕获所有内容。

如果数据一致性很重要,那么我建议您遵循我上面提到的基于存储过程的 SOP 方法。以下是此方法的高级概述:

  1. 使用存储过程,首先将所有更改转储到#temp 表中,
  2. 然后开始一个事务,
  3. 然后进行更改,将数据/更改从 #temp 表移动到实际表中,
  4. 然后在触发器中执行您想要的后续工作。如果这些是一致性检查,那么如果它们失败,您应该回滚事务。
  5. 否则,它将提交事务。

这几乎总是正确完成此类事情的方式。

【讨论】:

  • 已接受。再次感谢您的帮助!
【解决方案2】:

如果您的视图很小且被频繁查询并且您的下划线表很少更改,则您不需要“视图”。相反,您需要一个具有相同视图结果并由每个下划线表上的触发器更新的汇总表。

每次修改数据(插入、删除和更新)时都会触发一个触发器,但一次修改只会触发一次,无论是更新一条记录还是一百万行。您无需担心更新的大小。相反,更新频率是您关心的问题。

如果您有一个过程定期插入大量行,或一一更新大量行,您可以更改过程并在更新前禁用触发器,以便仅在过程结束之前更新汇总表,您可以在其中调用相同的“求和”过程并启用这些触发器。

如果您必须始终保持“摘要”最新,即使在大量事务期间(如果您的视图执行缓慢,我怀疑它是否非常有用或实用),您可以禁用这些触发器,在每次交易后自己做一些计算,在每次交易后更新汇总表,在您的程序中。

【讨论】:

  • +1 感谢您的回答,这基本上是我的解决方案现在的样子:我通过最后的过程调用更新汇总表的过程(类似于物化视图) INSERTs 的交易。
猜你喜欢
  • 1970-01-01
  • 2019-04-23
  • 2016-10-11
  • 1970-01-01
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 2010-11-23
相关资源
最近更新 更多