结构同步时需禁用“drop columns not exist in source”并关闭“rename columns”,手动勾选新增字段,避免隐式删除;同步前检查字段定义一致性,新增字段数据同步需单独配置。

结构同步时如何避免删除目标表已有字段
Navicat 的「结构同步」默认行为是让目标表结构完全匹配源表——这意味着目标表里多出来的字段(比如你手动加的 updated_by 或历史遗留的 is_deleted)会被直接 DROP。这不是 bug,而是设计逻辑:它按“全量覆盖”生成 DDL,不区分“新增”和“保留”。
真正能保住目标字段的,只有两个动作:禁用自动删除 + 手动筛选同步项。
- 进「结构同步」→「选项」→「高级」→ 取消勾选
Drop columns not exist in source(关键!这个选项默认常为启用) - 同一页里,也建议取消
Drop tables not exist in source和Drop views/stored procedures...,除非你明确要清理 - 比对完成后,不要点「全部运行」;在差异列表中,只勾选带「+」号的新增字段(蓝色/绿色标识),跳过带「−」号的待删除项
- 如果目标表有你必须保留的字段但源表没有,且该字段不允许为 NULL,提前在目标端执行
ALTER TABLE ... MODIFY COLUMN xxx ... DEFAULT ...,否则同步脚本可能因 NOT NULL 约束失败
为什么关掉 Drop columns 之后仍可能丢字段
关掉 Drop columns not exist in source 只是阻止显式 DROP 语句,但 Navicat 仍可能通过 ALTER TABLE ... CHANGE COLUMN 重定义字段——如果新旧字段名拼写接近(如 user_name → username),它会当成“改名”,顺手把旧字段删掉再建新字段。
这类隐式删除不会出现在预览 SQL 里,而是在执行时触发。规避方式很直接:
- 比对前,在「选项」中关闭
Rename columns(它在「高级」页底部,常被忽略) - 检查差异列表里的每一条「CHANGE」操作,确认是否真想改名;如果不是,手动取消勾选该项
- 对关键字段,用
SHOW CREATE TABLE对比源/目标两端的完整定义,尤其注意COLLATE、COMMENT、DEFAULT是否一致——Navicat 有时会因注释不同就判定为需 CHANGE
同步后字段值变 NULL 或被清空怎么办
这不是结构同步的直接结果,但常被误认为“字段丢了”。真实原因是:你在结构同步后立刻跑了「数据同步」,而新字段在目标表初始值为 NULL,Navicat 数据同步默认把 NULL 当作“待更新值”,把源表的真实值覆盖过去——但如果你没配好字段映射或 WHERE 条件,它可能反向把所有行的该字段刷成 NULL。
这种情况和结构同步本身无关,但时间线上紧挨着发生,容易混淆。应对要点:
- 结构同步和数据同步必须拆成两步操作,中间至少手动验证目标表字段定义和默认值
- 新增字段若含业务含义(如
status_v2),数据同步前务必进「表映射 → Options → Ignore columns」,把该字段加进去,防止误写 - 如果确实需要同步新字段的数据,不要依赖全表同步;在「数据同步 → 表映射 → Options」里启用
Use WHERE condition,限定范围(如id > 50000),并确认「冲突处理」设为Update existing records
最易被忽略的兼容性细节
MySQL 8.0+ 的 innodb_autoinc_lock_mode = 2(默认)会导致 INSERT 后 AUTO_INCREMENT 值跳跃,而 Navicat 结构同步若不小心同步了 AUTO_INCREMENT=xxx 值,会让后续插入 ID 不连续甚至冲突——这和字段删除无关,但同样发生在结构同步环节,且日志里不报错,只在业务 INSERT 时报 Duplicate entry。
所以,哪怕你已关掉所有 DROP 选项,只要没在「高级」里取消勾选 AUTO_INCREMENT,就仍可能埋下隐患。
真正的安全线不是“不删字段”,而是“不动任何已有字段的定义、约束、默认值、索引、注释——除非你明确知道后果”。Navicat 不做价值判断,它只忠实执行你勾选的规则。











