mysqldump默认不压缩且明文导出导致备份文件大,应配合gzip/zstd压缩、用--where过滤数据、跳过系统库和注释、禁用元数据,并对blob字段改用into outfile。

mysqldump 默认不压缩,大表直接导出就是明文 SQL
你看到的备份文件大,大概率是因为 mysqldump 没配压缩,它把所有数据原样转成 INSERT 语句写进文件——哪怕源表是 InnoDB 压缩页、或者字段本身有重复值,dump 出来全摊平了。特别是含大量文本、JSON 或长字符串的表,膨胀得最明显。
实操建议:
- 别依赖数据库层压缩,
mysqldump输出后立刻用gzip或zstd压缩,这是最简单有效的第一步 - 加
--skip-extended-insert反而会让文件更大(每行一条INSERT),默认的批量插入(INSERT INTO t VALUES (...),(...),...)更省空间 - 避免导出
information_schema或performance_schema这类系统库,它们不是业务数据,但可能意外被--all-databases拉进去
用 --where 限制导出范围,比事后删数据更省 IO
有些备份任务其实只要最近 3 个月的数据,但默认全表 dump 会读完整聚簇索引,IO 和临时内存都拉满,最终文件也大。用 --where 能让 mysqldump 在 SELECT 阶段就过滤,跳过不必要行。
常见错误现象:用 --where="created_at > '2024-01-01' 却发现导出失败或漏数据——这是因为 mysqldump 对 --where 的值不做 SQL 解析校验,引号、空格、特殊字符全靠你手写正确。
实操建议:
-
--where必须写成单引号包裹的完整条件表达式,例如:--where='status = "active" AND created_at >= "2024-01-01"' - 确保字段上有索引,否则
mysqldump仍会全表扫描,只是最后丢弃掉不匹配的行 - 对分区表,优先用
--ignore-table跳过旧分区,比--where更干脆
禁用注释和元数据能省 5%–15% 文件体积
mysqldump 默认在导出文件开头塞一堆 /*!40101 SET ... */ 注释、建表语句里的 ENGINE=InnoDB DEFAULT CHARSET=utf8mb4、甚至每张表的 /*!40014 ... */ 约束声明。这些对还原没坏处,但纯占空间,尤其当备份几十上百个表时,累积起来很可观。
实操建议:
- 加
--skip-comments干掉所有/*!...*/注释 - 加
--compact关掉额外换行和提示信息(注意:它也会禁用SET NAMES,还原前得手动补) - 如果确定目标库版本和源库一致,可加
--no-create-info(只导数据)、--no-create-db(跳过CREATE DATABASE)
zstd 比 gzip 压缩率高 30%,但需 MySQL 8.0.29+ 或手动安装
Linux 默认 gzip 压缩比一般在 3:1~4:1;zstd -T0 -19 能到 5:1~6:1,且多线程压缩更快。但 mysqldump 本身不支持 zstd,必须管道拼接。
容易踩的坑:
- 写成
mysqldump ... | zstd > backup.sql.zst是对的,但写成mysqldump ... | gzip | zstd就纯属浪费 CPU——先 gzip 再 zstd 不仅不增益,还可能因二次编码反而变大 - 某些老系统没装
zstd,执行时报command not found,得先apt install zstd或yum install zstd -
zstd的-T0表示自动用满 CPU 核数,生产环境若怕影响线上服务,建议显式设为-T2或-T4
真正难处理的是 BLOB 字段混在文本中——无论怎么调参数,含图片 base64、PDF 二进制的列,dump 出来还是大。这种场景该考虑用 SELECT ... INTO OUTFILE 分离存储,而不是硬压 mysqldump。











