mysqldump 导出时 cpu 爆表的根源是 mysqld 进程执行全表 select、解析行格式、刷 buffer pool 等操作;真正有效的限流需从 mysqld 内部约束,如禁用查询缓存、限制 innodb 并发线程数、调整缓冲池策略。

mysqldump 导出本身不直接吃 CPU,真正飙高的是 mysqld 进程——它在执行全表 SELECT、解析行格式、刷 Buffer Pool、抖查询缓存,而你只看到 top 里 mysqld 占 900%。
mysqldump 执行时 mysqld 为什么 CPU 爆表
导出不是“复制文件”,而是让 MySQL 服务端一条条 SELECT 出数据、拼成 INSERT 语句。这个过程触发大量内部操作:
-
SELECT *全表扫描 → InnoDB 遍历所有 page,rows值巨大时逻辑读爆炸 - 没加
--single-transaction时可能触发 MDL 锁,线程堆积等待,CPU 在上下文切换和锁竞争上空转 - 开启查询缓存(
query_cache_type = ON)时,dump 每扫一张表就失效重建一次,QUERY_CACHE_LOCKmutex 争抢严重 - 含
TEXT/BLOB字段时,MySQL 需额外内存做序列化和临时缓冲,sort_buffer_size和read_rnd_buffer_size设置不当会频繁落盘再读,IO 等待变 CPU 空转
限制 mysqldump 频率和并发线程的实际效果很弱
用 sleep 300 或写脚本控制调用间隔,对单次导出的 CPU 压力毫无缓解作用;开多个 mysqldump 并发导不同库,反而加剧 mysqld 的线程争抢和 Buffer Pool 污染。
-
nice -n 19 mysqldump只压低 dump 进程调度优先级,mysqld仍满频跑 -
ionice -c 3 mysqldump能降 IO 干扰,但 CPU 高是 mysqld 自身计算导致,和 dump 进程 IO 无关 - 真正该限的是 mysqld 的资源行为:比如临时设
SET GLOBAL innodb_thread_concurrency = 4,抑制并发扫描线程数
真正有效的导出限流方式:从 mysqld 内部约束
与其在外部卡 dump 脚本,不如让 MySQL 在导出期间“自我减速”。这些操作可在线执行,无需重启:
- 禁用查询缓存:
SET GLOBAL query_cache_type = OFF(若还在用) - 压低并发扫描能力:
SET GLOBAL innodb_thread_concurrency = 2(默认 0 表示不限,设小值可立竿见影) - 防止 dump 数据挤掉热数据:
SET SESSION innodb_buffer_pool_dump_pct = 0 - 对超大表强制分片导出:
mysqldump --where="id BETWEEN 1 AND 500000" db table > part1.sql,避免单次扫描过长 - 从库导出务必加
--skip-lock-tables,并确认slave_parallel_workers = 0或 SQL Thread 已停,否则 MDL 会卡住并行回放线程
phpMyAdmin 导出更危险:它默认启用压缩且不暴露底层参数
Web 界面勾选 “gzipped” 会强制 mysqld 启动压缩线程,额外吃 CPU;且无法控制 innodb_thread_concurrency 或跳过触发器。导出大表前务必:
- 取消勾选「压缩」选项
- 手动加 WHERE 条件,避免
SELECT * - 改用命令行:
mysqldump --single-transaction --skip-triggers --no-create-info db table > data.sql - 单表超百万行时,直接放弃 phpMyAdmin,用
pt-archiver分批导:pt-archiver --source h=localhost,D=db,t=table --where "id > 1000000" --limit 10000 --output-file data.sql
最易被忽略的一点:max_execution_time 和 wait_timeout 对导出完全无效——它们只管单条语句执行时长或连接空闲时间,而 mysqldump 是长连接持续拉取结果集,MySQL 不会中途中断它。真要控节奏,只能从 mysqld 的并发、缓存、缓冲池策略入手。











