BULK INSERT 默认不触发触发器,是SQL Server的设计行为而非bug;它绕过约束检查、日志记录和触发器执行,仅INSERT/UPDATE/DELETE等显式DML语句才激活触发器。
SQL Server 的
默认不触发触发器
直接结论:
命令默认绕过所有触发器(包括
),这不是 bug,是设计行为。它走的是高吞吐路径,跳过约束检查、日志记录和触发器执行——所以你看到“数据进去了,但触发器没动”,不是失效,是压根没被调用。
验证方式很简单:执行一次
后查
的执行日志(如果你有日志表)或加
语句,会发现什么都没输出。而用普通
就能立刻看到触发效果。
不受
控制,启用也没用
即使触发器状态是
,它依然不会运行
该行为在 SQL Server 所有主流版本(2016–2022)中一致
如何让批量导入触发触发器?用
替代
想保留触发器逻辑,就别用
。换成带触发器支持的等价操作:
或先
到临时表,再
。
关键点在于:只有显式
、
、
语句才会激活触发器;
、
、
的“快速加载”模式默认都不走这条路径。
临时表方案最稳妥:建
,
进去,再
如果源是文件,可用
配合
,它会触发触发器
注意:
创建新表时也不会触发目标表的触发器(因为表还不存在)
MySQL 的
同样跳过触发器
MySQL 用户容易踩的坑:用
导入 CSV 时,
和
全部静默失效——和 SQL Server 的
是同一类机制。
官方文档明确写:“
does not activate triggers.” 它绕过触发器、外键检查、甚至部分约束(取决于
)。所以你在触发器里写的日志插入、字段修正、权限校验,全都不会发生。
替代方案:用
循环或客户端分批提交(控制每批 ≤ 1000 行)
或者先
到中间表,再
若必须用
,所有业务逻辑得提前挪到 ETL 层或应用层做
触发器是否生效,第一步永远是确认操作类型是否被支持
很多人花几小时 debug 触发器逻辑,最后发现只是用了
(MySQL)、
(SQL Server)或
(MySQL)——这些命令根本不在触发器的监听名单里。
不要一上来就怀疑
条件、
值或事务隔离级别。先问自己:我当前执行的 SQL 命令,在对应数据库的文档里,是否明确写了 “triggers are activated”?如果没有,那就不是你的触发器有问题,是你的导入方式选错了。
尤其注意那些看起来像 DML 实际不是的语法:比如 MySQL 的
只触发
(8.0.19 前),SQL Server 的
在某些条件下也跳过触发器——这些细节不查文档很容易忽略。
BULK INSERTBULK INSERTAFTER INSERTBULK INSERTsys.triggersPRINTINSERTBULK INSERTENABLE TRIGGERis_disabled = 0INSERT ... SELECTBULK INSERTBULK INSERTINSERT INTO target_table SELECT * FROM OPENROWSET(...)BULK INSERTINSERT INTO target_table SELECT * FROM #stagingINSERTUPDATEDELETEBULK INSERTBCPSSIS#stagingBULK INSERTINSERT INTO real_table SELECT ...OPENROWSET(BULK ...)INSERT ... SELECTSELECT INTOLOAD DATA INFILELOAD DATA INFILEBEFORE INSERTAFTER INSERTBULK INSERTLOAD DATA INFILEsql_modeINSERT ... VALUESLOAD DATA INFILEINSERT INTO main_table SELECT ...LOAD DATAREPLACE INTOBULK INSERTLOAD DATAIFNEWINSERT ON DUPLICATE KEY UPDATEBEFORE UPDATEMERGE