sys.statements_with_errors_or_warnings 仅定位已成功执行但返回运行时错误(如error 1048、1062)或警告(截断、隐式转换)的sql,不包含语法错误(如error 1064),依赖performance schema启用及statement/sql/*插装开启,按digest聚合展示错误/警告频次、时间与数据库信息。

直接查sys.statements_with_errors_or_warnings能定位哪些SQL?
这个视图只记录**已成功执行但返回错误或警告的SQL语句**,不是语法错误(如ERROR 1064),而是运行时错误:比如ERROR 1048(列不能为NULL)、ERROR 1062(唯一键冲突)、WARNING(数据截断、隐式转换)。它不捕获解析失败的语句——那些根本没进执行器,压根不会出现在这里。
为什么sys.statements_with_errors_or_warnings默认可能为空?
它依赖Performance Schema中events_statements_summary_by_digest的聚合数据,而该表默认只统计最近约1万条语句(受performance_schema_events_statements_history_long_size限制),且错误/警告需满足两个前提:
-
performance_schema必须启用(MySQL 5.7+默认开,但有些运维会关) -
events_statements_history_long和events_statements_summary_by_digest对应的instrumentation必须开启,尤其是statement/sql/*类插装 - 如果错误发生后没被聚合(比如语句执行太快、digest未命中缓存),也可能漏掉
检查方式:SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'statement/sql/%' AND ENABLED = 'NO';,若有结果,需用UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME LIKE 'statement/sql/%';临时开启(重启失效)。
怎么查出“高频报错”的真实SQL?
视图本身带errors和warnings两列计数,但要注意:它按digest(规范化后的SQL模板)聚合,同一模板下不同参数的报错全算在一起。所以你要找的是errors + warnings总和高的digest,再反查原始语句:
SELECT digest_text, errors, warnings, first_seen, last_seen FROM sys.statements_with_errors_or_warnings ORDER BY errors + warnings DESC LIMIT 10;
关键点:
-
digest_text是脱敏后的SQL(如SELECT * FROM users WHERE id = ?),看不出具体参数,但能看出模式 - 想看某条digest对应的真实语句样本,得查
performance_schema.events_statements_history_long,用DIGEST字段关联 - 如果
last_seen时间很新,说明错误正在持续发生;如果first_seen很老但errors值不大,可能是偶发问题
容易被忽略的陷阱:错误计数不等于业务影响程度
一条每秒报错100次的INSERT(ERROR 1062)可能只是上游重试逻辑缺陷,而一条每天只错1次但导致事务回滚的UPDATE(ERROR 1205死锁)反而更危险。所以别只盯着数字排序,要结合:
- 错误码本身:
ERROR 1205(死锁)、ERROR 1213(锁等待超时)比ERROR 1062更值得优先处理 - 涉及的表和业务场景:核心订单表的错误,权重远高于日志表
- 是否伴随
sys.schema_table_lock_waits或x$innodb_lock_waits中的锁记录
真正的问题往往藏在“错误码+表名+调用频次”三者的交叉点里,而不是单看sys.statements_with_errors_or_warnings里的TOP 10。











