Performance Schema一启动就占用几百MB内存,是因为MySQL 8.0默认预分配events_statements_history_long等长历史表各128MB+,且启动即锁定,不随查询与否动态释放;需通过my.cnf调小*_size参数、限制max_digest_length等并重启生效。

Performance Schema 一启动就吃几百 MB,不是 bug,是它默认预分配内存的机制在起作用。
为什么刚启 MySQL 就看到 performance_schema 占用大量 RSS?
MySQL 8.0 默认开启 performance_schema=ON,且默认启用全部 instruments 和 consumers。其中 events_statements_history_long、events_transactions_history_long 这类“长历史表”会各自预分配 128MB+ 内存——不是按需申请,而是 mysqld 启动时就划走。哪怕你从不查这些表,内存也早已被锁住。
常见现象:mysqld 进程 RSS 突然多出 300–500MB;SHOW PROCESSLIST 看不到异常连接;但执行 SELECT * FROM sys.memory_global_total 或查 performance_schema.memory_summary_global_by_event_name 会发现 memory/performance_schema/ 相关项占比超 40%。
哪些配置项真正决定 P_S 内存开销?
关键不是“开不开”,而是“开多少”。以下参数直接控制预分配量,必须写进 my.cnf 的 [mysqld] 段并重启才生效:
-
performance_schema_events_statements_history_long_size = 10000(默认 20000) performance_schema_events_transactions_history_long_size = 10000-
performance_schema_max_digest_length = 256(默认 4096,每条 SQL 摘要省 3.7KB) -
performance_schema_max_sql_text_length = 1024(默认 4096) -
performance_schema_max_statement_stack = 10(默认 30)
注意:performance_schema_max_file_instances 等实例数限制也影响内存,尤其当库表数量多时,file_instances 默认不限可能导致占用飙升到 GB 级。
为什么 SET GLOBAL 关不掉长历史表内存?
UPDATE performance_schema.setup_consumers SET ENABLED = 'NO' WHERE NAME IN ('events_statements_history_long', ...) 只能停掉数据采集,但已预分配的内存不会释放——这是设计使然。P_S 的内存是启动时 mmap 分配的,运行时无法归还 OS。
真正生效的方式只有两个:
- 改配置文件 + 重启 MySQL(推荐,彻底释放)
- 临时关闭整个 P_S:
SET GLOBAL performance_schema = OFF(不建议生产环境用,且重启后失效)
另外,很多 DBA 在宝塔里改了 /www/server/mysql/my.cnf,但 MySQL 根本没读它——8.0 只认 /etc/my.cnf 等固定路径。确认配置生效前,先跑:mysqld --defaults-file=/www/server/mysql/my.cnf --verbose --help 2>/dev/null | head -5,不报错再重启。
查当前 P_S 内存到底花在哪?
启用 memory instruments 后(需在 my.cnf 加 performance-schema-instrument='memory/%=ON' 并重启),才能查真实分布:
SELECT EVENT_NAME, CURRENT_NUMBER_OF_BYTES_USED / 1024 / 1024 AS mb FROM performance_schema.memory_summary_global_by_event_name WHERE EVENT_NAME LIKE 'memory/performance_schema/%' ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 10;
重点关注这几项:
memory/performance_schema/events_statements_history_longmemory/performance_schema/events_transactions_history_long-
memory/performance_schema/file_instances(若值异常高,说明performance_schema_max_file_instances没设限)
别只看 CURRENT_NUMBER_OF_BYTES_USED,它反映的是当前持有量;TOTAL_NUMBER_OF_BYTES_ALLOCATED 才是历史总分配量,能帮你判断是否频繁分配/释放导致碎片。
最常被忽略的一点:P_S 的内存占用和你是否查询它完全无关——只要它开着,且相关 instruments/consumers 没禁,那块内存就早被划走了。调优动作必须前置到配置层,而不是等出问题再查表关 consumer。


















