默认mysqldump导出含LONGBLOB/LONGTEXT表易卡死,因单次SELECT *触发max_allowed_packet超限;应改用SELECT INTO OUTFILE(需secure_file_priv路径)、调大服务端/客户端packet、显式字符集、禁用校验,并在应用层精简字段+游标分页+流式读取。

直接用默认 mysqldump 导出含 LONGBLOB 或 LONGTEXT 的表,大概率在读取阶段卡住、报 MySQL server has gone away——这不是网络问题,而是单次查询拉回的数据量超过了服务端或客户端的缓冲上限。
为什么 mysqldump 会卡死在大字段上
根本原因是:默认行为下,mysqldump 对每张表执行一次全量 SELECT *,而大字段(尤其是 Base64 编码后的 LONGBLOB)会让单行体积暴涨。哪怕只有几千行,总数据量也可能轻松突破 max_allowed_packet 限制,触发服务端断连或客户端超时。
常见错误现象包括:
-
Packet too large(服务端拒绝接收) -
MySQL server has gone away(客户端连接被服务端主动关闭) - 导出进程长时间无响应,CPU 占用低但内存持续上涨
用 SELECT INTO OUTFILE 绕过客户端缓冲
这是最稳的导出方式——由 MySQL 服务端直写磁盘,不经过客户端内存缓冲,天然规避大字段对客户端的冲击。但它有硬性前提:
- 必须确认
secure_file_priv值(执行SHOW VARIABLES LIKE 'secure_file_priv'),导出路径只能落在该目录下,比如/var/lib/mysql-files/ - 目标路径是数据库服务器本地路径,不是你本机;填
/tmp/export.csv却没权限写入服务端,会直接失败 - 导出语句需显式包裹字段,尤其含换行符时:
SELECT id, content FROM tbl WHERE ... INTO OUTFILE '/var/lib/mysql-files/tbl_part1.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ',' LINES TERMINATED BY '\n'; - 不支持多表或
JOIN,适合单表分段导出
导入 LOAD DATA INFILE 时的关键配置
即使导出成功,导入仍可能失败。核心是让服务端和客户端同时“撑开肚子”:
- 服务端
max_allowed_packet必须 ≥ 单行最大长度(例如含 20MB Base64 字段的行),建议设为512M并重启mysqld - 客户端连接也要同步调大:
mysql --max-allowed-packet=512M -u root db_name,否则 MySQL 客户端库会在传输层截断 - 字符集必须显式声明:
LOAD DATA INFILE '/var/lib/mysql-files/tbl_part1.csv' CHARACTER SET utf8mb4 ...,否则Incorrect string value错误高发 - 导入前关掉校验:
SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET sql_log_bin=0;,避免逐行检查拖慢速度
应用层同步时必须避开 SELECT *
如果走程序(Python/Go)读取再写入,千万别用 SELECT * 拉整张表——大字段会把进程内存和网络带宽瞬间打满:
- 只查必要字段:
SELECT id, title, content比SELECT *少传几个 MB,延迟下降明显 - 用游标分页替代
LIMIT offset, size:WHERE id > ? ORDER BY id LIMIT 1000,避免大偏移量扫描 - 启用流式读取(如 Python 的
cursor.unbuffered()或 Go 的Rows.Next()迭代),防止结果集全加载进内存 - 字段精简 + 游标分页 + 流式读取,三者缺一不可;漏掉任一环,都可能在 10 万行后 OOM
真正难的不是“怎么导”,而是判断哪一段数据里藏着那个 50MB 的异常 LONGBLOB——它会让整批迁移突然卡死。建议先导出前用 SELECT MAX(LENGTH(content)) FROM tbl 探底,再决定分块大小和包限制值。


















