mysql performance_schema.triggers 表不记录触发器执行次数和耗时,execution_count 和 timer_wait 恒为 null,因其仅存储元数据,未实现运行时统计;可靠监控需在触发器内写入 innodb 日志表。

MySQL 原生不记录触发器的执行次数和耗时,performance_schema.triggers 表在 8.0+ 版本中仅存元数据(如定义、事件类型),字段 EXECUTION_COUNT 和 TIMER_WAIT 恒为 NULL —— 这是关键前提,别白查。
为什么 SELECT * FROM performance_schema.triggers 查不到执行统计?
MySQL 的 performance_schema 确实有 triggers 表,但自 5.7 引入起就未实现运行时计数逻辑。官方文档明确说明该表仅反映触发器注册状态,不采集执行指标。你执行:
SELECT TRIGGER_NAME, EXECUTION_COUNT, TIMER_WAIT FROM performance_schema.triggers WHERE TRIGGER_NAME = 'my_trigger';
结果中 EXECUTION_COUNT 总是 NULL,不是权限或配置问题,是功能缺失。
用 information_schema.TRIGGERS 只能看定义,不能看执行
这个视图只提供静态信息,比如触发时机(ACTION_TIMING)、事件类型(EVENT_MANIPULATION)、SQL 体(ACTION_STATEMENT),但完全不包含任何运行痕迹。常见误操作包括:
- 误以为
SELECT * FROM information_schema.TRIGGERS WHERE TRIGGER_NAME = 'xxx'能返回调用次数 - 在慢日志里搜
TRIGGER关键字——慢日志记录的是 DML 语句本身,不标记“此处触发了 N 个触发器” - 依赖
SHOW TRIGGERS输出的Statement字段判断是否执行——它只是定义文本,不是执行日志
真正可行的执行监控:手动日志表 + 原子写入
唯一可靠的方式是在触发器体内部插入日志,且必须保证日志写入与主事务一致(即同事务提交或回滚)。示例:
DELIMITER //
CREATE TRIGGER log_after_insert_user
AFTER INSERT ON users
FOR EACH ROW
BEGIN
INSERT INTO trigger_log (
trigger_name,
table_name,
event_type,
executed_at,
new_id
) VALUES (
'log_after_insert_user',
'users',
'INSERT',
NOW(6), -- 微秒精度,便于排序
NEW.id
);
END //
DELIMITER ;
要点:
- 日志表
trigger_log必须是InnoDB引擎,否则无法参与主事务 - 避免在日志中调用
SLEEP()、UUID()或其他可能失败的函数,防止触发器中断主 DML - 若需统计频次,用
SELECT COUNT(*) FROM trigger_log WHERE trigger_name = 'xxx' AND executed_at >= '2026-06-18',别依赖触发器自己维护计数器变量 - 日志表要定期归档,否则
INSERT变慢会拖累主表性能
间接推断法:结合 binlog + 客户端行为分析
当无法改触发器时,可从外部反推执行频次:
- 开启
binlog_format = ROW,解析 binlog 中对目标表的变更事件数(例如mysqlbinlog /var/lib/mysql/mysql-bin.000001 | grep -c 'table_map.*users'),再减去已知非触发路径的 DML 次数 - 在应用层埋点:所有向触发器关联表(如
users)发送INSERT/UPDATE/DELETE的代码路径,统一打日志或上报指标 - 用
performance_schema.events_statements_history_long查最近执行过的语句,过滤出影响目标表的 DML,再人工对照触发器逻辑估算——这仅适用于低频调试,不可用于生产监控
最易被忽略的一点:触发器没有独立的「执行栈」可见性。它的耗时完全并入父 DML 语句的执行时间中,slow_query_log 里看到的慢查询,可能是 DML 本身慢,也可能是它带的触发器慢,二者无法分离——除非你把触发器逻辑拆出来单独压测。











