触发器内查information_schema或performance_schema特别慢,因其是动态生成视图,每次查询需遍历内存结构、采集统计快照、校验权限,高并发下易锁元数据缓存,导致DML阻塞;且不走索引、无查询缓存,还会延长事务提交时间、加剧主从延迟。

触发器里查 information_schema 或 performance_schema 为什么特别慢
因为这些表不是普通表,而是运行时动态生成的视图,每次查询都要遍历内存结构、采集统计快照、做权限校验——尤其在高并发写入场景下,information_schema.TABLES 这类表可能锁住元数据缓存,导致所有后续 DML 等待。
- MySQL 的
information_schema表底层调用的是存储引擎接口,查COLUMNS或STATISTICS会触发全库表扫描式元数据加载,哪怕只查一张表的索引信息,也可能拉取整个库的列定义缓存 -
performance_schema虽然轻量些,但开启events_statements_history后,每条语句都会写入环形缓冲区;触发器里再反向查它,等于在写入高峰期做一次同步读取+解析,极易触发 mutex 竞争 - 更隐蔽的问题:某些版本(如 MySQL 5.7.20 前)对
information_schema查询不做 query cache,且无法走任何索引——WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME = 't'依然全表扫描
SELECT COUNT(*) FROM information_schema.COLUMNS 在 BEFORE 触发器中执行的后果
这句看起来 harmless,实际是“写入路径上的定时炸弹”:它会在主事务还没提交前,就申请对元数据字典加共享锁(S lock),而此时如果有其他连接正在 ALTER TABLE 或 CREATE INDEX,就会形成锁等待链,最终让 INSERT/UPDATE 卡住数百毫秒甚至超时。
- 现象:单行插入耗时从 2ms 涨到 800ms,
SHOW ENGINE INNODB STATUS显示waiting for table metadata lock - 根本原因:触发器执行上下文和主 DML 共享同一事务 ID,但元数据锁(MDL)不按事务隔离级别释放,而是按语句粒度持有直到语句结束
- 替代方案:把这类元数据检查移到应用层或定时任务中预热缓存;真需要运行时判断,改用
SHOW COLUMNS FROM t(虽然也慢,但至少不走information_schema的重载路径)
哪些系统表查询在触发器里绝对要禁用
不是所有系统表都一样危险,但以下三类在触发器内出现,基本等于主动给写入链路加阻塞点:
-
information_schema.PROCESSLIST:每次查询都要抓取全部连接状态快照,CPU 和锁开销双高 -
performance_schema.events_waits_current:实时等待事件表,高并发下极易因 buffer ring 满而阻塞写入线程 -
sys.schema_table_statistics(MySQL sys schema):底层依赖多次 JOINinformation_schema,性能比直接查原表还差
真正安全的替代方式,是提前把需要的元数据(比如某张日志表是否存在、字段类型是否匹配)固化成配置项,由应用或部署脚本注入,而不是在每次触发时现场查。
误用系统表查询引发的连锁反应
你以为只是慢了一点,实际上可能已经破坏了事务边界和复制稳定性:
- 在主库触发器里查
information_schema,会导致 binlog event 写入延迟,从库回放 lag 突增——因为主库事务提交时间被拉长,GTID 分配滞后 - 如果触发器逻辑被封装进存储过程再调用系统表,MySQL 8.0+ 会额外记录
statement/sql/show_fields类事件,进一步放大performance_schema自身负载 - 最麻烦的是排查困难:慢日志里只记
INSERT INTO t,不记触发器内的SELECT FROM information_schema,除非你手动开启long_query_time=0并捕获完整堆栈
真正关键的不是“能不能查”,而是“查的时机是否在事务临界路径上”——只要它出现在 BEFORE/AFTER 触发器里,就已经站在了性能最敏感的位置。


















