“直接同步”卡在1%不动是因为Navicat默认采用客户端中转模式,需将源表全量数据(含JSON/TEXT/BLOB)加载至本地内存解析并生成SQL,千万级表易触发OOM和GC暂停;应启用“直接表/视图复制”让MySQL服务端直连执行INSERT INTO...SELECT,或改用mysqldump命令行绕过GUI瓶颈。
为什么“直接同步”会卡在 1% 不动?
navicat 默认走的是「客户端中转」路径:先把源表数据全量拉到本地内存,再拼成 insert 语句发给目标库。遇到千万级表时,select * 本身可能只花 200ms,但 navicat 要把每行 json 字段 decode 成字符串、缓存全部 resultset、再逐条生成 sql——这个过程常吃光 2gb 内存,触发 gc 暂停,界面就卡死不动。
常见误判是以为“网络慢”或“目标库写入慢”,其实 show processlist 里源库和目标库都空闲,真正堵点在 Navicat 进程内部。
- 检查是否启用了
自动列宽或实时行数统计:这两个功能在同步预览阶段就会扫描前 1000 行,含 TEXT/BLOB 时直接拖慢初始化 - 确认是否勾选了
验证外键约束或启用事务:大表同步时单事务提交失败会导致整批回滚重试 - 观察任务管理器里 Navicat 的内存占用是否持续 >1.5GB:这是典型的全量加载瓶颈
改用“直接表复制”跳过客户端解析
Navicat 的 数据传输 功能里有个隐藏开关:直接表/视图复制。它不经过 JDBC ResultSet,而是让 MySQL 服务端直连(需源库和目标库能网络互通),用 INSERT INTO ... SELECT 在服务端完成搬运。
实测对比:同步一张 1200 万行的订单表,普通模式耗时 47 分钟且中途崩溃 2 次;开启该选项后 6 分钟完成,内存占用稳定在 180MB。
- 必须确保源库和目标库的 MySQL 用户有
SELECT和INSERT权限,且能互相访问(非 localhost) - 目标表必须已存在,且字段顺序、类型完全一致;否则会报
Column count doesn't match - 如果源表有自增主键,目标表也要提前建好同名自增列,否则会因
INSERT ... SELECT忽略自增值而报错
手动分批 + 关闭事务比调大批量更有效
很多人调高 每批记录数 到 50000 仍慢,是因为 Navicat 在批量模式下仍默认开启事务——每批都 BEGIN; ...; COMMIT;,导致日志刷盘频繁。真正有效的做法是关事务 + 小批次 + 并行。
例如同步一张含 BLOB 的用户表,实测最优组合是:每批 5000 行 + 禁用事务 + 并发连接数 = 3。这样既避免单批内存溢出,又减少锁等待,总耗时比默认设置快 3.2 倍。
- 在
数据传输向导的「高级」页,取消勾选使用事务(不是“启用事务”) -
并发连接数不要设过高:超过 CPU 核心数后反而因上下文切换拖慢,4 核机器设 3 最稳 - 若目标表已有索引,同步前先
ALTER TABLE t DROP INDEX idx_xxx,同步完再重建——索引维护开销常占总时间 40% 以上
什么时候该放弃 Navicat 改用命令行?
当表大小超过 5GB,或需要同步带分区、全文索引、生成列的复杂表时,Navicat 的 GUI 层封装反而成了累赘。此时直接用 mysqldump --no-create-info --skip-triggers --single-transaction 导出数据,再用 mysql -h target_db --force 导入,全程无 GUI 阻塞,还能加 --compress 减少网络传输量。
特别注意:Navicat 对大于 2GB 的 SQL 文件支持极差,导入时容易报 Packet for query is too large,而命令行工具没这限制。
- 导出前先运行
SELECT table_name, round(((data_length + index_length) / 1024 / 1024 / 1024), 2) AS size_gb FROM information_schema.TABLES WHERE table_schema = 'db' AND table_name = 'big_table';确认真实大小 - 如果源库和目标库在同一台服务器,优先用
LOAD DATA INFILE(需secure_file_priv路径一致),速度比任何工具都快 - Navicat 的“忽略错误继续执行”在大表同步中不可靠——它可能跳过关键约束冲突却不报错,导致数据不一致











