会,触发器因共享事务上下文并持有锁而必然阻塞其他查询;其执行时加锁范围覆盖全部sql操作,易引发严重性能问题,推荐改用异步队列解耦。

会,而且阻塞是同步、不可回避的——只要触发器在跑,主事务就卡着,连接不释放,其他查询就得排队等锁。
触发器执行时为什么必然阻塞其他查询
触发器不是后台线程,它和原始 INSERT/UPDATE/DELETE 共享同一个事务上下文。MySQL 会把触发器里的所有 SQL(包括 SELECT、INSERT、UPDATE)都纳入当前事务的锁持有范围。这意味着:
- 触发器里查一张没索引的配置表,会加 next-key lock,阻塞其他事务对该范围的插入
- 触发器里执行
INSERT INTO log_table SELECT ... FROM huge_table,等于把全表扫描+行锁一起塞进主事务里 - 哪怕只是
SELECT COUNT(*) FROM information_schema.COLUMNS,也会申请元数据锁(MDL),让后续ALTER TABLE或其他 DML 卡住
现象很典型:SHOW PROCESSLIST 看到一堆 Query 状态、Time 值持续上涨;HikariPool-1 active=80 idle=0;Java 层开始抛 SQLTransientConnectionException: Connection is not available。
哪些触发器操作最容易引发明显阻塞
不是所有触发器都一样危险,但以下三类一旦出现,基本等于主动给写入链路埋雷:
-
information_schema.PROCESSLIST:每次调用都要抓取全部连接快照,CPU 和 MDL 锁双高 -
SELECT ... FROM remote_db.table或任何跨库查询:网络延迟直接变成事务延迟,超时即卡死 -
INSERT INTO t1 SELECT * FROM t2 WHERE ...(尤其t2行数 > 10 万且无有效索引):锁持有时间与结果集大小正相关,极易拖垮批量操作
特别注意:BEFORE 触发器里做 SELECT 比 AFTER 更危险——它发生在主语句执行前,连主键插入路径都能卡住。
如何快速验证是不是触发器在阻塞
别猜,直接观测:
- 查活跃触发器:
SELECT EVENT_OBJECT_TABLE, ACTION_TIMING, EVENT_MANIPULATION FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA = 'your_db' - 看慢日志里是否集中出现某张表的 DML:
mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log | grep -E "(INSERT|UPDATE).*target_table" - 临时禁用(仅限排查):
SET SESSION sql_log_bin = 0; DROP TRIGGER IF EXISTS your_trigger_name;,对比禁用前后同一条语句的SHOW PROCESSLISTTime值变化
如果从 45 秒降到 200ms,不用再往下查了。
真正能解阻塞的替代方案
触发器不是不能用,而是不能承担“实时联动”这种重活。可行路径只有一条:落库即走,异步消费。
- 建一张轻量
trigger_queue表,字段最少只需table_name、row_id、event_type、created_at - 触发器里只干一件事:
INSERT INTO trigger_queue (table_name, row_id, event_type) VALUES ('orders', NEW.id, 'INSERT') - 用外部进程(Python/Go)定时拉取:
SELECT * FROM trigger_queue WHERE status = 'pending' ORDER BY id LIMIT 100 FOR UPDATE SKIP LOCKED,处理完再标为 done
这个模式下,主 DML 耗时稳定在毫秒级,而复杂逻辑、外部调用、重试降级都交给应用层控制——这才是生产环境该有的节奏。











