登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL performance_schema.setup_consumers 怎样开启长语句历史

来源:17golang原创

时间:2026-11-03 03:39:42 332浏览 收藏

如果你想在 MySQL 中保留最近一段时间执行过的 SQL,重点不是直接查询 events_statements_history_long,而是先打开对应的 consumer。最小配置通常是把 events_statements_history_long 设为 YES,同时确认上游的全局、线程和当前语句消费者没有关闭。

官方地址:https://dev.mysql.com/doc/refman/8.4/en/performance-schema-setup-consumers-table.html

这张表保存的是跨线程、已经结束的最近语句事件;它是一个有限窗口,不是永久 SQL 日志。窗口满了以后,旧行会被新行淘汰,所以“查不到”不一定代表语句没有执行。

一、先分清 current、history 和 history_long

Performance Schema 的语句事件可以按三个观察范围理解:

  • events_statements_current:关注每个线程当前正在处理的语句。
  • events_statements_history:保留每个线程最近结束的一小段语句历史。
  • events_statements_history_long:把所有线程已经结束的语句汇总到一个全局的长历史窗口。

因此,history_long 适合回答“刚才有哪些线程执行过什么语句”,不适合替代慢查询日志、审计日志或永久业务流水。官方文档还说明,这张表没有索引,读取时要控制返回列和时间范围。

MySQL Performance Schema 消费者层级与语句长历史的静态关系说明图
图1:消费者层级说明图,展示上游开关与语句长历史之间的静态关系;这不是数据库控制台截图。

二、检查 setup_consumers 的上游开关

先看当前配置,不要直接修改:

SELECT NAME, ENABLED
-- 只查看消费者开关,先确认采集链路是否被上游截断
FROM performance_schema.setup_consumers
WHERE NAME IN (
  'global_instrumentation',
  'thread_instrumentation',
  'events_statements_current',
  'events_statements_history',
  'events_statements_history_long'
)
ORDER BY FIELD(
  NAME,
  'global_instrumentation',
  'thread_instrumentation',
  'events_statements_current',
  'events_statements_history',
  'events_statements_history_long'
);

这里最容易忽略的是层级关系:上游 consumer 为 NO 时,下层即使写成 YES 也不能产生预期采集结果。实务上至少要确认:

  • global_instrumentation 为 YES,否则整体监控链路可能关闭。
  • thread_instrumentation 为 YES,否则线程级语句事件不会按预期采集。
  • events_statements_current 为 YES,再看 history 与 history_long 的开关。

如果只是临时观察 SQL,通常不必把所有 waits、stages 和 transactions 的历史都一起打开。先打开语句这一条链路,范围更容易控制。

三、动态开启 events_statements_history_long

setup_consumers.ENABLED 可以修改。只打开全局语句长历史时,可以执行:

UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
-- 只打开跨线程的语句长历史,避免把其它事件历史一起扩大
WHERE NAME = 'events_statements_history_long';

SELECT NAME, ENABLED
-- 立即回读目标开关,确认修改落在正确的 consumer 上
FROM performance_schema.setup_consumers
WHERE NAME = 'events_statements_history_long';

官方文档说明,对 setup_consumers 的修改会立即影响监控。不过“立即生效”只表示新的采集配置开始参与判断,不会把开启前已经结束的语句补写回历史表。

如果需要按线程保留短历史,可以单独打开 events_statements_history;如果只关心所有线程的最近事件,则保持 history_long 为 YES,并结合容量和查询范围使用。

四、设置容量并读取最近语句

events_statements_history_long 保存最近的全局语句事件。N 的默认值由服务器启动时自动调整;要明确设置容量,应使用启动参数 performance_schema_events_statements_history_long_size,改完后按实例的发布流程重启。

读取时优先选出结束时间、线程、摘要和耗时字段:

SELECT THREAD_ID,
       EVENT_NAME,
       SQL_TEXT,
       TIMER_START,
       TIMER_END,
       ROWS_EXAMINED,
       ROWS_AFFECTED
-- 只取最近结束的语句,避免无索引历史表返回过多列
FROM performance_schema.events_statements_history_long
WHERE SQL_TEXT IS NOT NULL
ORDER BY TIMER_END DESC
LIMIT 100;

这张表记录的是已经结束的语句事件,并且是跨线程的全局窗口。窗口满后,插入新事件会淘汰最旧的行;容量越小,越容易在排查前被后续流量覆盖,容量越大则要结合实例资源和监控成本评估。

MySQL events_statements_history_long 全局语句历史窗口和淘汰关系说明图
图2:全局语句历史窗口说明图,展示已结束事件、容量 N 与旧记录淘汰的静态关系;这不是运行截图或实际输出。

五、为什么打开后仍然查不到语句

现象优先检查原因边界
目标 consumer 是 YES,但没有新记录检查上游 global/thread/current 开关上游关闭会让下层设置失去作用
刚执行的语句不在表中确认语句已经结束事件结束前不会进入 history_long
稍早的语句消失了查看最近写入量和容量全局窗口满后会淘汰最旧行
SQL_TEXT 为空或结果不完整检查查询列和事件类型不要把历史表当作完整审计记录

还有一个常见误区:把查询历史表本身当作“打开开关后自动拥有过去记录”。consumer 只影响之后的事件采集,历史数据不会凭空回填;如果需要长期留存,应使用更适合持久化的日志或监控链路。

六、一个可复用的最小操作顺序

  1. 查询 setup_consumers,确认上游开关。
  2. 只把 events_statements_history_long 改为 YES。
  3. 执行一组目标 SQL,再查询长历史表。
  4. 按实例流量设置启动时容量,不把它当成永久存储。
  5. 排查时先区分“未结束、被截断、被淘汰、列筛选”四类原因。

常见问题

只开启 events_statements_history_long 就够了吗?

不一定。要先确认上游消费者和线程级采集没有关闭;层级上的 NO 可能让下层设置不产生效果。

history_long 是不是永久 SQL 记录?

不是。它只保存有限数量的最近已结束语句,容量满后会淘汰旧行,也不应该替代审计或慢查询日志。

修改 setup_consumers 需要重启吗?

消费者表的修改会立即影响监控;但 history_long 的明确容量通常通过启动参数设置,容量调整要按实例流程重启。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>