navicat同步后源目标表行数不一致的根本原因是源表显示行数为innodb估算值(information_schema.tables.table_rows),误差可达40%~50%,且不同步实时更新;同步过程无锁、无一致性快照,期间源表并发写入导致基准与实际脱节;可靠校验必须用select count(*)而非界面显示值。
navicat 同步后源表和目标表行数不一致,根本原因不是同步出错,而是你看到的“源表行数”本身就不准——它压根不是真实行数,只是 mysql 对 innodb 表的估算值。
Navicat 显示的行数来自 INFORMATION_SCHEMA.TABLES.TABLE_ROWS
这个值是 MySQL 内部维护的统计快照,对 InnoDB 引擎而言:
• 它不随每次写入实时更新,而是基于采样估算
• 官方明确说明误差可达 40%~50%,属于正常行为
• 即使你刚执行完 INSERT 或 DELETE,TABLE_ROWS 也可能完全没变
• ANALYZE TABLE 对 InnoDB 的 TABLE_ROWS 基本无效(仅影响查询优化器统计)
同步过程中源表被并发写入
Navicat 的「数据同步」默认不加锁、不开启一致性快照,典型行为是:
• 开始时读一次源表的 COUNT(*)(或直接取 TABLE_ROWS)作为“基准”
• 同步耗时几秒到几分钟,期间应用仍在往源表 INSERT/UPDATE/DELETE
• 目标表写入完成,但源表实际已多出/少掉若干行
• 最终对比时,你拿的是“同步结束时的真实 COUNT(*)” vs “同步开始时的估算 TABLE_ROWS”,自然对不上
未提交事务干扰了可见性
如果同步启动前源库存在长事务(BEGIN 未 COMMIT),会导致:
• Navicat 在某个隔离级别下读到部分未提交数据(幻读)
• SELECT COUNT(*) 的结果取决于事务是否已提交,而 TABLE_ROWS 完全不感知事务状态
• 执行 SELECT * FROM information_schema.INNODB_TRX; 可查到活跃事务 ID
• 这类事务常驻会持续污染行数判断,尤其在业务高峰期
真正可靠的校验方式只有一种
别依赖 Navicat 界面右下角那个数字,也别比对两个 TABLE_ROWS:
• 同步前,手动执行 SELECT COUNT(*) FROM your_table;,记下结果
• 同步中,确保源表无任何写入(停业务 or FLUSH TABLES WITH READ LOCK;)
• 同步后,立刻再跑一遍 SELECT COUNT(*) FROM your_table;,和目标表结果比对
• 若仍不一致,问题才出在同步逻辑本身(如字段映射丢失、WHERE 条件误配、字符集截断)
最常被忽略的一点:很多人在同步后直接右键刷新 Navicat 表节点,以为这样就拿到了最新 TABLE_ROWS ——其实只是重新读了一次过期的估算值。真要验证,必须亲手敲 COUNT(*)。











