触发器调用存储过程比直接写SQL慢十倍,因其每次调用均引发完整上下文切换、权限校验与执行计划重解析,且在事务内同步阻塞;叠加DETERMINISTIC缺失、隐式类型转换、嵌套查询扩锁及无语句级缓存,批量场景下开销指数级放大。
因为每次调用都触发一次完整上下文切换:参数拷贝、权限校验、执行计划重解析,而触发器本身又在事务内同步阻塞执行。实测一个含三层嵌套查询的存储过程,在500 QPS下会让触发器平均延迟从 0.8ms 涨到 12ms。
不是函数逻辑本身慢,而是调用机制带来的叠加损耗:
DETERMINISTIC 声明缺失时,MySQL无法缓存执行计划,每次调用都重新生成VARCHAR 给 INT 参数)会触发隐式转换,导致索引失效SELECT 或 PERFORM(PostgreSQL),等于在触发器里又嵌了一层查询,锁范围扩大以下情况几乎必然引发性能雪崩:
JOIN 或 ORDER BY
NEW/OLD 字段重名,导致值被意外覆盖,逻辑静默失效INOUT 参数——MySQL 对其批量处理极不稳定,容易丢数据READS SQL DATA,优化器误判为无副作用,跳过关键优化保留存储过程复用价值,但绕过调用瓶颈:
CASE WHEN status=1 THEN 'active')直接展开写进触发器体trigger_queue),由后台任务轮询消费INSERT ... ON DUPLICATE KEY UPDATE 替代“查再更”类逻辑,彻底避开存储过程调用DETERMINISTIC + READS SQL DATA + 所有输入字段都有索引最常被忽略的一点:触发器里哪怕只调一次存储过程,只要它内部查了没索引的字段,整个写入链路就会卡在那个点上——不是看代码行数,而是看实际执行计划里有没有 type: ALL。