因为默认mysqldump单线程逐行读取并生成insert,对大表易触发锁等待、缓冲区溢出或超时;且--single-transaction依赖快照,长事务可能导致undo日志被purge而报死锁或binlog错误。

导出大表时为什么 mysqldump 会卡住或超时?
因为默认情况下 mysqldump 使用单线程、逐行读取 + 生成 INSERT 语句,对千万级以上表极易触发锁等待、网络缓冲区溢出或客户端超时。更关键的是它默认开启 --lock-tables(MyISAM)或 --single-transaction(InnoDB),后者虽不锁表但依赖一致性快照,若事务运行太久,可能被 purge 线程清理掉 undo 日志,直接报错 MySQL Error 1205: Deadlock found when trying to get lock 或 Could not read term position from binlog。
实操建议:
- 加
--skip-lock-tables(仅限 InnoDB,且确保无 DDL 同时执行) - 强制分块导出:用
--where="id BETWEEN 1 AND 1000000"手动切片,配合脚本循环 - 禁用自动提交和键检查:导出时加
--no-autocommit --disable-keys,导入时才重建索引 - 调大客户端超时:
--connect-timeout=3600 --max-allowed-packet=512M
导入慢的真正瓶颈不是磁盘,而是 SQL 解析和索引维护
直接用 mysql -u user db_name 导入一个 10GB 的 <code>INSERT 文件,实际耗时 80% 花在解析每条语句、校验约束、实时更新二级索引上。即使 SSD 也扛不住。
实操建议:
- 导入前手动关闭唯一性检查:
SET unique_checks=0; SET foreign_key_checks=0; - 用
--extended-insert(默认开启)保证每行 INSERT 包含多条值,减少语法解析次数 - 导入后一次性重建索引:
ALTER TABLE t ENGINE=InnoDB;(适用于无主键变更场景) - 避免用
source命令进 MySQL CLI 导入——它单线程且无进度反馈;改用mysqlimport或原生LOAD DATA INFILE(需先转成 CSV)
替代方案:用 --tab 直接导出为文本,绕过 SQL 解析层
mysqldump --tab 不生成 INSERT,而是调用 SELECT ... INTO OUTFILE 写出纯文本(如 t.txt)和建表语句(t.sql)。导入时用 LOAD DATA INFILE,速度能提升 3–5 倍,且支持并发加载多个文件。
注意点:
- 导出目录必须是 MySQL 服务端可写路径(
--tab=/var/lib/mysql-files),不是客户端本地路径 - 字段分隔符默认是制表符,导入时要显式指定:
LOAD DATA INFILE '/var/lib/mysql-files/t.txt' INTO TABLE t FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n'; - 该方式不导出视图、存储过程,只适合纯数据表迁移
- 若表含 BLOB/TEXT 字段,需确认
secure_file_priv允许读写对应路径
真正的大表(>100GB)别硬扛 mysqldump
当单表超过 100GB,mysqldump 的内存占用和临时文件膨胀会失控,且无法中断续传。此时应切换工具链:
- 物理备份优先选
Percona XtraBackup:支持流式压缩、加密、增量、恢复时自动重放 binlog - 逻辑导出可用
mydumper(多线程 + 事务级切分 + 支持断点续传),搭配myloader并发导入 - 跨版本或云迁移考虑
mysqlpump(MySQL 5.7+),它内置并行导出,但对老版本兼容差
最常被忽略的一点:无论用哪种方式,务必在导出前执行 ANALYZE TABLE,否则统计信息陈旧会导致优化器误判,让 dump 过程本身变慢。











