1. 触发器是特殊的存储过程,在事件发生时执行;DML触发器在INSERTUPDATEDELETE时触发,DDL触发器在像CREATEALTERDROP时触发,Logon触发器在建立会话时触发
  2. 触发器和触发它的语句被认为是一个操作,如果回滚的话,这两个一起回滚,如果这个语句是外层事务的一部分的话,外层事务也会被回滚;触发器也可以级联修改相关表,但是这样的操作,还是使用级联引用完整性约束更高效一些
  3. 相对于CHECK约束来说,触发器可以完成更加复杂的约束检查,在触发器中还可以引用其他表;触发器还可以定制错误消息,使得传递给客户的消息更有意义;可以为同一类型的操作定义多个触发器
  4. AFTER Triggers,在数据修改完成后触发,通常用来:
  • 对修改进行审计
  • 实现表之间关于关系的复杂的规则
  • 实现行之间的默认值或者计算值

通常基于触发器的代码都可以被其他形式代码替换,比如审计可以使用SQL Server Audit,表之间的关系可以使用外键约束,默认值和计算值可以通过DEFAULT约束和持久化计划列来实现,不过触发器的优点之一是它可以实现复杂的逻辑,这也是上述的替代者可能无法完成的;触发器执行回滚的话,数据修改语句会被回滚,如果语句被包含在另外一个事务中的话,这个事务也会被回滚

  1. INSTEAD OF Triggers,用来执行替换代码而不是引发触发器的语句,常用于更新不能直接更新的视图
  1. DML触发器即可以使用T-SQL语句实现,也可以使用托管代码实现;更新等操作可能会修改多行,触发器只会触发一次,而不是为每行都触发触发器,因此设计触发器时,要设计成处理多行的触发器
  1. 触发器中的inserteddeleted虚拟表只在触发器执行时的触发器中代码中可用,也就是说如果触发器中执行了存储过程,这个存储过程是不能访问这两张表的
  1. 在添加触发器时,非常重要的一点就是不要打断已有的应用程序的逻辑,除非是有意为之;使用触发器时一个常见的错误时,在进行更新等操作时,触发器引起了数据修改(比如向审计表中插入了数据),导致返回的被更新行数不是更新操作影响的行数,而是触发器影响的行数,这样对于使用更新操作影响的行数的应用程序来说就使用了不恰当的值,通过SET NOCOUNT ON语句来避免这样的错误,大部分触发器都应该包含这个语句
  1. 触发器中可以返回行集,这将带来副作用,不建议使用,可以通过在SQL Server中将disallow results from triggers设置为1,禁止这样的能力
  1. 通常来说,约束性能比触发器更高,触发器调试起来也非常复杂,因为触发器不是在直接触发他们的代码中可见的,触发器增加了数据处理的时间,对于AFTER TRIGGER来说,如果决定禁止数据修改,它要执行ROLLBACK语句,这导致语句已经完成的工作被取消,如果能直接避免进行数据修改,可以提高性能,约束都是在数据修改前执行的,因此通常可以获得更好的性能,但是触发器可以执行复杂逻辑,这是约束不能是实现的
  2. SQL Server 2005以前,inserteddeleted表本质上是处理日志的视图,这些表中的数据每次需要的时候都要重新构建;从SQL Server 2005开始,在tempdb数据库中提供了一个特殊的rowversion表,这个表用来保存触发器的inserteddeleted表的数据副本,这样提高了触发器的效率,但也意味着如果过度使用触发器,将导致tempdb产生性能问题
  3. TRUNCATE TABLE语句不会触发AFTER DELETE触发器
  1. 一些数据库提供了BEFORE TRIGGER,即在操作前执行的触发器,这些操作也会被执行,而INSTEAD OF TRIGGER则是只执行触发器中的代码,不会执行引起触发器的语句
  1. 触发器中可以包含INSERTUPDATEDELETE语句,这些语句可能会触发另外一张表中的触发器,这些触发器被认为是嵌套触发器;可以控制是否允许嵌套触发器,默认是允许的,可以在服务器级别进行配置;嵌套触发器失败将导致所有语句被取消;嵌套触发器不允许在同一个触发器事务中被触发两次,在第二次更新同样的表的时候,触发器不能调用自身;嵌套和递归的触发器更加难以调试,通常使用PRINT语句打印错误信息帮助调试
  1. 默认禁止递归触发器,可以通过SET RECURSIVE_TRIGGERS ON选项开启递归触发器
  • 需要小心设计和全面的测试,保证不能超过32层的嵌套限制
  • 很难控制表更新的顺序
  • 通常可以使用非递归逻辑代替
  • 递归触发器分为直接递归(触发器在同一张表上执行更新操作,导致同样的触发器被触发)和间接递归(触发器导致另外一个触发器被执行,另外一个触发器又导致这个触发器被执行),SET RECURSIVE_TRIGGERS ON选项只会影响直接递归,如果要禁止间接递归,需要关闭嵌套递归选项
  1. UPDATE函数用来决定指定的列是否进行了更新,这个函数检测的是指定的列是否包含在UPDATE语句的SET语句中,而不是指定的列实际值发生了修改,如果要判断实际值修改的话,应该要比较inserteddeleted
  2.  当为同一个事件创建多个触发器时,不能指定触发器被触发的顺序;sp_settriggerorder只允许指定触发器是第一个还是最后一个被触发,只针对DML触发器
  1. 许多情况下使用其他选择比使用触发器更好:
  • 检查值时使用约束
  • 提供默认值时通常使用DEFAULT约束
  • 引用完整性通常使用外键
  • 基于其他列值维护一列值时,使用计算列或者持久化计算列persisted computed columns
  • Pre-calculating Aggregates使用indexed views,这个和计算列的区别就是Pre-calculating Aggregates可以基于其他表中的其他列