假设我有下表:
Create Table [dbo].[Test_IP]
(
[IP] varchar(40),
[IPType] varchar(6)
)
这张表上有更多的触发器,但它们都是 AFTER 触发器,它是一个包含许多表、视图和存储过程的大型数据库,并且被多个进程使用。
我添加了一个日志表和这样的触发器
Create Table [dbo].[Log_Test_IP]
(
[Action] varchar(10),
[IP] varchar(40),
[IPType] varchar(6)
)
GO
Create Trigger MYTR_Log_Test_IP_INS On [dbo].[Test_IP] After insert AS
BEGIN
insert into [dbo].[Log_Test_IP]([Action],[IP],[IPType])
select 'Insert', [IP], [IPType] from inserted
END
GO
Create Trigger MYTR_Log_Test_IP_DEL On [dbo].[Test_IP] After delete AS
BEGIN
insert into [dbo].[Log_Test_IP]([Action],[IP],[IPType])
select 'Delete', [IP], [IPType] from deleted
END
GO
现在我进入了有趣的部分:当我直接插入Test_IP
表格时,我可以看到插入触发器正在工作,但是当它从应用程序或服务正常工作时(我不知道它做了什么),我不知道在日志表中看到任何插入记录,我只能看到“删除”记录,即使它在开始时是空的。
我的结论是有一些方法可以绕过触发器,数据库中有很多触发器和存储过程,我不知道去哪里找。
所以,我的问题是如何绕过触发器?
触发器不会在几个场景中运行。
1)显然如果触发器被禁用
2) 如果触发器被标记为NOT FOR REPLICATION并且 DML 是由复制分发代理发出的。
3) 如果用户具有 ALTER TABLE 权限并且正在执行 BULK INSERT、BCP 或 SqlBulkCopy 等,并且禁用了 FIRE_TRIGGERS 选项。
您不能绕过触发器,除非禁用,否则它将始终根据创建条件触发。您可以使用临时对象或 context_info() 使触发器短路,但根据您的描述,这不太可能。
你的触发器应该被触发,但它不是,这有点令人担忧。我认为分区切换甚至可以发挥作用。我会远离探查器或跟踪,因为它们已被弃用。
我将从跟踪表上的活动开始,这是由 Grant Friitchey 编写的扩展事件脚本,它将捕获该表上的所有 ADHOC 查询。
来自 Grant Friitchey 编写的 SQL Central 的源代码 - The Scary DBA
我还希望捕获在审计日志中更新或插入表的事件。
Stack Overflow 的 Nic 编写了以下代码:
堆栈溢出源的 Nic 提供的 SQL 审计代码源。
作为最后的手段,我会阅读所有存储过程并查看引用该表的任何内容。
堆栈溢出的链为您提供了一个简短的片段,这里还有更多用于确定存储过程中使用的表。
与往常一样,在开发环境中对此进行测试,并谨慎和适当的 QA 将其传播到生产环境中。
再次感谢Grant、Chains和Nic的贡献!
您可以尝试使用 SQL Server Profiler,看看应用程序发生了什么。应将事件 SP:StmtCompleted 添加到跟踪