根本原因是mysql对json/xml字段的原生操作无法走索引、无法批量化且强制串行执行:json函数如json_contains不支持b+树索引,需逐行解析字符串;xml函数如extractvalue需加载全文并构建dom树;二者均导致cpu陡增、锁等待延长及事务时间拉长。

XML 和 JSON 字段在触发器中处理时效率明显降低,根本原因不是字段类型本身,而是 MySQL(及多数主流数据库)对这类字段的原生解析、生成和校验操作无法走索引、无法批量化、且强制串行执行。
MySQL 中 JSON 字段在触发器里触发全表扫描
常见错误是:在 AFTER INSERT 触发器里写类似 SELECT ... FROM logs WHERE JSON_CONTAINS(data, '"error"') AND created_at > NOW() - INTERVAL 1 HOUR。问题在于:
-
JSON_CONTAINS()、JSON_EXTRACT()等函数无法利用普通 B+ 树索引,即使你在data字段上建了索引,type仍是ALL - 如果没建
GENERATED COLUMN + 虚拟索引,所有 JSON 查询都等价于对整列做字符串解析 —— 每行都要加载、解析、匹配 -
JSON_VALID(NEW.data)这类校验看似轻量,但在批量插入(如INSERT ... SELECT)时,会为每一行重复执行完整 JSON 解析,CPU 开销陡增
XML 字段在触发器中触发隐式转换和锁升级
MySQL 的 XML 类型支持弱,实际多用 TEXT 存储,但触发器里调用 ExtractValue() 或 UpdateXML() 会带来额外负担:
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
-
ExtractValue(xml_col, '//user/@id')内部会把整个 XML 字符串加载进内存并构建 DOM 树,哪怕只取一个属性 - 若触发器中用
UPDATE修改含XML字段的表,InnoDB 可能因字段长度不可预估而放弃行级锁优化,退化为间隙锁甚至表锁 - XML 函数不支持参数化,无法复用执行计划;每次调用都要重新编译解析路径表达式
JSON/XML 处理导致事务时间拉长,放大锁等待
触发器内处理 JSON/XML 往往伴随读写其他表(比如日志、配置、审计),而这类操作本身慢,又卡在事务里:
- 一个插入触发器里执行
INSERT INTO audit_log (...) VALUES (..., JSON_OBJECT('old', OLD.data, 'new', NEW.data))——JSON_OBJECT()是 CPU 密集型,且生成的 JSON 字符串越长,写入audit_log的 IO 越大 - 高并发下,多个事务同时在触发器里解析 JSON,竞争 CPU 和 buffer pool,
Innodb_row_lock_waits明显上升 - 更隐蔽的是:JSON 字段若定义为
NOT NULL DEFAULT (JSON_OBJECT()),MySQL 在触发器中初始化时也会触发默认值计算逻辑,增加不可见开销
真正要命的不是“能不能做”,而是“做了之后你根本看不出它正在拖垮并发”。很多线上事故里,触发器看起来只干了一件事——拼个 JSON 写日志,但压测一上来,QPS 掉一半,SHOW PROCESSLIST 里全是 Updating 状态,却查不到慢查询日志——因为慢在触发器内部,不在主 SQL。










