根本诱因是max_allowed_packet不足,真正拖慢同步的是MySQL静默跳过含BLOB的整行、Navicat反复重试及内存爆满后降级为单行拉取,尤其在无主键表的Comparing records阶段需全表加载内存排序比对。
max_allowed_packet 不足是根本诱因,但真正拖慢同步的不是“卡住”,而是 MySQL 服务端静默跳过整行、Navicat 反复重试、内存爆满后降级为单行拉取 —— 尤其在无主键表上,Comparing records 阶段会把全表加载进本地内存排序比对。
为什么BLOB字段会让同步任务变慢到几乎停滞
navicat 同步大字段时的瓶颈不在网络带宽,而在三处硬限制叠加:
-
max_allowed_packet过小 → 服务端拒绝整条含 BLOB 的 INSERT,不报错,只跳过该行;Navicat 检测不到失败,继续发下一条,但实际数据已丢失,后续校验阶段反复重传 - 源表缺失主键或唯一索引 → Navicat 无法做哈希分片,被迫进入
Comparing records阶段,把整张表 SELECT 到本地内存排序比对;macOS/Linux 下极易触发 swap 或 OOM,Windows 也吃光 8GB+ 内存 - Navicat 默认用 Client export 模式 → 数据先从源库拉到本地,再拼 SQL 发给目标库;BLOB 字段一多,本地内存和磁盘 IO 直接打满,CPU 持续 100%
怎样快速定位哪张表在拖慢同步
别猜,直接查元数据。在 Navicat 中执行:
SELECT table_name, column_name, data_type, character_maximum_length
FROM information_schema.COLUMNS
WHERE table_schema = 'your_db'
AND data_type IN ('blob', 'mediumblob', 'longblob', 'text', 'mediumtext', 'longtext')
ORDER BY table_name, ordinal_position;
重点关注 mediumblob 和 longblob 字段,尤其是平均长度 >512KB 的表。这些就是同步时最可能卡死的“罪魁”。
必须改的三项配置(缺一不可)
只调 max_allowed_packet 是无效的,必须组合生效:
- MySQL 服务端:修改
my.ini(Windows)或/etc/my.cnf(Linux/macOS),在[mysqld]段加max_allowed_packet = 256M,然后**停止服务 → flush tables → 启动服务** - Navicat 同步任务设置:在「数据同步 → 高级」中启用
Use compression(压缩传输),并取消勾选Commit every batch(避免远程频繁刷盘) - 同步方式强制切为
Server export (SQL file):右键表 → 导出向导 → Export Method 选此项,并确认目标库secure_file_priv已设为可写路径(SHOW VARIABLES LIKE 'secure_file_priv')
遇到同步中途失败,千万别重头来
Navicat 15+ 的同步任务不支持断点续传。一旦失败,已导入的数据不会回滚,但未完成部分也不会记录进度。更糟的是,它不会告诉你哪一行失败了。
稳妥做法只有两个:
- 对含 BLOB 的大表,**提前拆分**:用
WHERE id BETWEEN ? AND ?分批同步,每批控制在 5000 行以内(避免单批超max_allowed_packet) - 彻底绕开 Navicat GUI:用命令行直连,例如:
mysqldump --host=src --user=u --password=p --skip-extended-insert --single-transaction --max-allowed-packet=512M db table | mysql --host=dst --user=u --password=p db
真正麻烦的从来不是 BLOB 本身,而是 Navicat 在无主键、无压缩、未切片的情况下,把整张百万行的 BLOB 表当成一个内存对象来搬运 —— 它不是慢,是设计上就不该这么用。











