Navicat数据同步默认启用事务且使用REPEATABLE READ隔离级别,读操作加S锁并持有MDL,易导致锁等待和阻塞;无法配置NOLOCK或快照读,因其不支持SQL Server语法且不暴露隔离级别控制;安全替代方案是mysqldump配合--single-transaction分批导出导入。
navicat 同步数据本身不会自动加 nolock 或启用快照读——它用的是标准可重复读(repeatable read)事务隔离级别,读操作默认加共享锁(s锁),大表全表扫描或长事务下极易引发锁等待甚至阻塞写入。
Navicat 数据同步是否走事务?怎么查它在锁什么
Navicat 的「数据同步」功能默认开启事务,且不提供隔离级别配置项。一旦同步涉及大表或 WHERE 条件未命中索引,就会触发全表扫描 + 持有 MDL(metadata lock)和行级 S 锁,后续的 ALTER TABLE、INSERT、UPDATE 都会被卡在 Waiting for table metadata lock 状态。
- 立刻执行
SHOW PROCESSLIST;,重点看State列含Locked、Waiting for table metadata lock或长时间Sending data的线程 - 用
SELECT * FROM information_schema.INNODB_TRX WHERE TRX_STATE = 'RUNNING' AND TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60;找出运行超 1 分钟的事务 - 别只盯 Navicat 进程 ID——后台可能还有未提交的应用事务正在 hold 住同一张表
为什么不能在 Navicat 同步里加 NOLOCK 或快照读
NOLOCK 是 SQL Server 语法,MySQL 不支持;MySQL 对应的是 READ UNCOMMITTED 隔离级别或 SELECT ... FOR UPDATE/LOCK IN SHARE MODE 的显式控制,但 Navicat 同步界面完全不暴露这些选项。所谓“快照读”在 MySQL 中依赖 MVCC 和当前事务的 read view,而 Navicat 启动的同步会新建一个事务,其快照点就是 START TRANSACTION 时刻,无法跳过已提交但未刷新的变更。
- 强行在 Navicat 同步前执行
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;无效:同步过程内部会重置会话状态 - 试图在同步 SQL 中手写
SELECT * FROM t1 IGNORE INDEX (PRIMARY) WHERE ...也没用:Navicat 不允许改底层同步语句逻辑 - 真正可控的读一致性,只能靠应用层分页 + 主键范围查询(如
WHERE id BETWEEN ? AND ?),避开全表扫
替代方案:绕开 Navicat 同步,用无锁方式导数据
对生产库安全同步,核心是避免长事务、避免全表扫描、避免持有 MDL。Navicat 的图形化同步不是为高可用场景设计的,应切换为更可控的命令行组合。
- 导出侧用
mysqldump --single-transaction --skip-triggers --no-create-info:利用 InnoDB MVCC 快照,不锁表 - 导入侧禁用外键检查:
SET FOREIGN_KEY_CHECKS = 0;开头,SET FOREIGN_KEY_CHECKS = 1;结尾,但仅限单次导入脚本内 - 大表分批次导入:用
mysql -e "SELECT * FROM t1 WHERE id >= 1000000 AND id 导出 CSV,再用 <code>LOAD DATA INFILE(注意 secure_file_priv 路径限制) - 终极方案:用
pt-online-schema-change做同步,它通过影子表 + 触发器捕获增量,全程不锁原表
最容易被忽略的一点:Navicat 同步失败后残留的临时表或未清理的事务,可能让锁持续数小时。每次中止同步,务必手动检查 INNODB_TRX 并确认没有 TRX_STATE = 'ACTIVE' 的长事务挂着。磁盘满、binlog 日志写满、max_connections 耗尽,也会表现为“锁表现象”,但根源不是锁——得先看 df -h 和 SHOW GLOBAL VARIABLES LIKE '%log%';。


















