navicat 17模型同步会卡住alter table和insert,因其默认启用repeatable read事务、全表扫描触发mdl锁与间隙锁,且不支持algorithm=inplace;预览阶段执行select count(*)等操作易阻塞写入,超时后锁残留成“幽灵锁”。

Navicat 17 的模型同步(Model Synchronization)不是“比对完就执行”,它会在后台启动长事务、全表扫描源模型对应表、全程持有 MDL 锁,直到整个流程结束——这意味着哪怕你只改了一个字段名,生产表也可能被锁住数分钟,且超时后不会自动释放锁。
为什么模型同步会卡住 ALTER TABLE 和 INSERT
模型同步底层调用的是结构比对 + DDL 生成 + 批量执行,但关键问题在于它默认行为不可控:
- 强制以
REPEATABLE READ启动事务,哪怕你只点 Preview,也会先 SELECT 全表来构建差异,触发间隙锁和 MDL 读锁 - 不支持在界面上指定
ALGORITHM=INPLACE或LOCK=NONE,即使 MySQL 8.0 支持在线 DDL,Navicat 仍可能退化为 COPY 模式 - 预览阶段(Preview DDL)默认开启,而
SELECT COUNT(*) FROM table_name这类统计查询若没索引,就会全表扫+持锁,阻塞其他写入 - Socket Timeout 默认 30 秒,但一个大表加索引实际耗时可能超 5 分钟,超时后 Navicat 断连,但 MySQL 事务和 MDL 锁仍在 —— 变成“幽灵锁”
如何安全执行模型同步而不影响线上业务
别依赖“取消”或“重试”,要从源头掐断锁扩散路径:
- 关闭预览:进入 Preferences → DDL → uncheck “Preview DDL before execution”;否则每次点 Preview 都会新开事务并持锁
- 手动拆分操作:不要一次性同步全部表。右键单张表 → “Synchronize to Database”,限定范围,缩短锁持有时间
- 提前检查 DDL 兼容性:在目标库手动执行
SHOW CREATE TABLE table_name,确认引擎是InnoDB、无FULLTEXT索引(会强制 COPY)、无外键级联(可能触发隐式锁) - 设置客户端保活:连接属性 → Advanced → Socket Timeout 设为
1800,勾选 Keep connection alive(间隔填60),并在 SQL Query 框中加SET SESSION wait_timeout = 28800;
同步中途卡住,怎么快速定位和清理残留锁
模型同步失败后最危险的不是报错,而是后台事务没回滚、MDL 锁还挂着。此时不能只看 Navicat 界面,必须进数据库查真实状态:
- 立刻执行
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_STARTED ,重点关注 <code>TRX_QUERY是否含SELECT或ALTER,以及TRX_STATE是否为lock wait - 查 MDL 等待链:
SELECT OBJECT_NAME, LOCK_TYPE, LOCK_MODE, LOCK_STATUS FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'PENDING';,找出谁在等哪张表 - 确认线程已失联但事务还在?运行
SELECT ID, USER, HOST, COMMAND, TIME, STATE FROM INFORMATION_SCHEMA.PROCESSLIST WHERE TIME > 300 AND COMMAND = 'Sleep';,对这类 ID 执行KILL [ID](不是KILL QUERY) - 如果怀疑是重启残留,直接执行
FLUSH TABLES WITH READ LOCK; UNLOCK TABLES;强制刷新 MDL 缓存(需 SUPER 权限)
模型同步本质是“高风险批量 DDL 封装”,它不暴露执行计划控制、不支持分段、不校验锁代价。真正安全的做法,是把模型变更转为人工评审后的最小化 SQL 脚本,用 mysql 命令行 + --single-transaction 或 pt-online-schema-change 执行——Navicat 只该用来建模和导出 DDL,不该用来直接上生产。











