MySQL内存占用高需从配置、运行时行为及外部环境三方面排查:调优innodb_buffer_pool_size(42G–50G)、tmp_table_size/max_heap_table_size(256M–1G)、max_connections(按峰值×1.5);用performance_schema定位内存消费者;监控长事务、大查询、多语句及Group Replication等隐性开销;确保tmpdir独立且容器内存限制充足。

查关键配置参数
内存占用高,往往从配置开始。重点关注几个核心参数:
- innodb_buffer_pool_size:InnoDB缓冲池大小,通常应设为物理内存的60%–80%。比如62G内存服务器,设12G就明显偏低(易引发频繁刷盘),设64G又可能超限(有OOM风险);合理值应在42G–50G之间。
- tmp_table_size 和 max_heap_table_size:两者需保持一致,控制内存临时表上限。16M太小,复杂JOIN或GROUP BY易溢出到磁盘,反而拖慢并增加I/O压力;建议调至256M–1G(视单次查询数据量而定)。
- max_connections:若设为5000但实际活跃连接仅20个,每个连接仍会预分配sort_buffer、join_buffer等,造成隐性浪费。建议按峰值连接数×1.5预留,再结合线程池使用。
看实时内存分布
别只信top里的mysqld进程RSS值——那是总驻留内存,要拆开看谁在“吃”:
- 运行:SELECT event_name, sys.format_bytes(CURRENT_NUMBER_OF_BYTES_USED) FROM performance_schema.memory_summary_global_by_event_name ORDER BY CURRENT_NUMBER_OF_BYTES_USED DESC LIMIT 10; ——快速定位前10大内存消费者,如
memory/innodb/buf_buf_pool占13GB属正常,但memory/sql/Query_cache或memory/temptable/physical_ram异常飙升就要警惕。 - 查用户级消耗:SELECT user, host, SUM(current_number_of_bytes_used)/1024/1024 AS MB FROM performance_schema.memory_summary_by_account_by_event_name GROUP BY user, host ORDER BY MB DESC LIMIT 5; ——发现某业务账号持续占65MB以上,大概率存在未关闭游标、长事务或低效批量操作。
- 确认全局用量:SELECT SUM(CAST(REPLACE(current_alloc,'MiB','') AS DECIMAL(10,2))) FROM sys.memory_global_by_current_bytes WHERE current_alloc LIKE '%MiB%'; ——若结果远低于top显示值(如仅2GB vs top报56GB),说明大量内存由非PFS追踪路径分配(如JIT解析、复制缓存、jemalloc内部碎片等)。
盯连接与SQL行为
很多内存暴涨不是配置问题,而是运行时行为触发:
- 执行SHOW FULL PROCESSLIST;,过滤
State为Sending data、Copying to tmp table或长时间Locked的线程,这类SQL常伴随大排序、大分组、全表JOIN,极易耗尽tmp_table_size限制并转入磁盘临时表,同时拉高内存峰值。 - 注意
Command列为Query但Time超过60秒的连接,可能是未提交事务持有undo页、锁等待堆积,导致buffer pool中脏页无法及时刷出、历史版本链持续膨胀。 - 警惕客户端一次性发送多语句(multiple statements)或超长bulk insert(如单条INSERT含上万VALUES)。这类操作在SQL解析、语法树构建阶段就会预分配大量内存,且释放滞后。
排查特殊组件与外部影响
有些内存占用藏得深,不在常规SQL路径里:
-
Group Replication / XtraDB Cluster:如
memory/group_rpl/Gcs_xcom::xcom_cache占1GB,说明集群通信缓存积压,检查网络延迟、节点同步延迟或事务冲突率是否升高。 -
存储过程/函数密集调用:大量动态SQL拼接、嵌套循环、未释放的游标,会在每个会话的
thd::main_mem_root中累积分配,重启连接才能清理。 - 临时目录位置:默认/tmp可能空间小或被其他进程挤占,导致磁盘临时表写入失败,MySQL被迫重试或扩大内存缓冲——务必用tmpdir = /data/mysql/tmp指向独立大容量分区。
-
容器或cgroup限制:Docker中若设置了
--memory=4g但MySQL配置了12G buffer pool,系统会OOM kill mysqld;需确保容器内存limit ≥ MySQL最大理论内存(buffer_pool + max_connections × per_thread_buffers)。










