并行导出大量小表应优先用mydumper而非mysqldump,因其复用连接、批量查元数据、原生分文件;若用mysqldump则需控制并发数≤max_connections的70%、禁用--lock-tables、分目录存储防inode耗尽。

mysqldump 并行导出大量小表时 CPU 和 I/O 常常卡死
单线程 mysqldump 遇到几百上千张小表,耗时主要卡在连接建立、权限校验、表结构查询这些重复开销上,不是磁盘慢,是客户端和 MySQL 服务端反复握手拖垮了吞吐。并发启动多个 mysqldump 进程能破局,但必须控制数量——超过 max_connections 或磁盘随机 I/O 队列深度(如 Linux 的 vm.swappiness 或 SSD 队列压力)反而更慢。
实操建议:
- 先查
SHOW VARIABLES LIKE 'max_connections';,并发数别超过它的 70%,例如 200 就最多起 140 个 dump 进程 - 用
--skip-extended-insert减少单条 SQL 长度,避免 MySQL 解析器在大量小 INSERT 上卡住 - 加
--single-transaction而非--lock-tables,否则表越多锁冲突越频繁 - 别把所有输出重定向到同一个文件或目录;SSD 对同一目录下高频创建小文件敏感,建议按库/前缀分目录,例如
dump/db1/、dump/db2/
用 mydumper 替代 mysqldump 是更稳的选择
mydumper 是专为多表并发设计的工具,它复用连接、批量获取表元数据、支持正则过滤、原生分文件写入,比手写 shell + mysqldump 组合靠谱得多。但它默认不压缩,导出体积大;且对 MySQL 8.0+ 的角色权限(ROLE)、部分 JSON 函数兼容性弱。
实操建议:
- 安装后先跑
mydumper --version,确认 ≥ v0.11.1(修复了 8.0.29+ 的INFORMATION_SCHEMA.COLUMNS字段顺序问题) - 用
-t 8控制线程数,配合-o /path/to/dump/,它会自动按库/表建子目录并生成schema.sql+table.sql+metadata - 加
--regex '^db_name\..*'只导指定库,避免information_schema等系统库干扰 - 若需压缩,别用
-c(内置 gzip 不稳定),导完用pigz -p 4并行压缩单个.sql文件
并发写入多个 .sql 文件时遇到 “No space left on device” 却 df 显示有空余
这不是磁盘满,是 inode 耗尽。每张小表一个 .sql 文件(尤其 mydumper 默认行为),几千张表就几千个文件,而很多 XFS/ext4 文件系统默认每 GB 只配几千个 inode。df -i 一查常发现 Usage 100%。
实操建议:
- 建 dump 目录前先看
df -i /path/to/dump,不够就换分区,或提前用mkfs.xfs -i size=512重建(慎用于生产盘) -
mydumper加--chunk-filesize 32(单位 MB),强制合并小表到同个文件,减少文件数 - 用
mysqldump时改用--databases db1 db2一次性导整个库,再用csplit拆文件,比每表一文件省 inode
恢复时 source 大量小文件极慢,且容易中断
MySQL 客户端 source 是串行执行,每个 .sql 文件都要重新解析连接、切换数据库、校验权限。1000 个文件 = 1000 次 round-trip,网络延迟和客户端开销直接吃掉 60%+ 时间。
实操建议:
- 恢复前先用
cat *.sql | mysql -u... -p... db_name合并管道输入,跳过客户端文件管理层 - 关掉 autocommit:
mysql -e "SET autocommit=0;",再导入,否则每个 INSERT 都刷日志 - 临时调大
innodb_log_file_size和innodb_buffer_pool_size(需重启),不然小事务频繁刷盘 - 别用
mysqlimport试图加速——它只认LOAD DATA INFILE格式,而 dump 出来的是 INSERT,格式不匹配
真正麻烦的是跨版本恢复:MySQL 5.7 导出的 CREATE TABLE 里带 STATS_SAMPLE_PAGES,在 8.0.33+ 会报错;这种细节得提前 grep 检查,不能等恢复卡住才翻日志。










