navicat 16结构同步postgresql前必须确认目标库为10+版本且用户具备select、usage on schema、create on schema权限;否则会静默跳过新特性或报“schema not found”错误。

结构同步前必须确认目标库连接权限和版本兼容性
Navicat 16 的「结构同步」功能对 PostgreSQL 版本和用户权限非常敏感。若目标库是 PostgreSQL 9.6 或更早,同步会静默跳过 GENERATED 列、IDENTITY 列或分区表定义;PostgreSQL 10+ 才被完整支持。连接用户必须同时具备 SELECT(读取源库 pg_class/pg_attribute)、USAGE on schema(访问目标 schema)、以及 CREATE on schema(生成 DDL)权限——缺 USAGE 会导致“schema not found”错误,而非明确提示权限不足。
- 右键源库 →「结构同步」→ 左侧选源 PostgreSQL 连接,右侧选目标 PostgreSQL 连接
- 在「对象选择」页,**务必取消勾选 Functions / Procedures / Triggers / Sequences**:这些对象的定义常因换行、注释缩进、空格数量不同触发误报,且结构同步不该承担逻辑变更职责
- 点击「选项」→ 勾选「忽略列顺序」和「忽略默认值中的引号」:PostgreSQL 对
DEFAULT '2023-01-01'和DEFAULT "2023-01-01"视为不同,但语义一致
比对结果里大量 ALTER TABLE MODIFY COLUMN 是正常还是危险?
出现 MODIFY COLUMN 说明 Navicat 检测到字段类型实际变化,比如 TEXT → JSONB、VARCHAR(50) → VARCHAR(100),这属于合理差异。但若看到 CHARACTER VARYING(255) → TEXT 却无业务需求,大概率是源库建表语句曾被手动执行过 ALTER TABLE ... TYPE TEXT,而 Navicat 逆向时未捕获该操作上下文——此时需人工核对源库 pg_get_serial_sequence() 和 pg_get_expr() 输出,确认是否真有类型变更。
- PostgreSQL 中
ENUM新增值会被转成重建整个类型(CREATE TYPE ... AS ENUM+ALTER TABLE ... ALTER COLUMN ... TYPE),线上大表慎用;应提前在目标库手动执行ALTER TYPE xxx ADD VALUE 'new_val' - 含
GENERATED ALWAYS AS (...) STORED的计算列,Navicat 默认不比对表达式内容,只比对是否为 generated —— 若表达式已变更但标记未变,差异会被漏掉
导出 SQL 脚本后执行报错:syntax error at or near “IF”
这是 PostgreSQL 版本兼容问题。Navicat 生成的 CREATE TABLE IF NOT EXISTS 在 PostgreSQL 9.1+ 支持,但 CREATE INDEX IF NOT EXISTS 直到 9.5 才引入,COMMENT ON COLUMN IF EXISTS 则要 11+。若目标库是 9.3,脚本里所有带 IF NOT EXISTS 的语句都会报错。
- 导出前点「高级」→ 取消勾选
Use IF NOT EXISTS for CREATE statements - 导出文件后,全局替换
COMMENT ON COLUMN为COMMENT ON COLUMN(不加 IF EXISTS),再手动验证目标库是否已存在该注释 - Navicat 默认不加事务包装,大结构变更建议手动在脚本开头加
BEGIN TRANSACTION;,结尾加COMMIT;,避免中途失败导致半截状态
中文注释乱码或字段描述显示为空
根本原因不是数据库字符集设错,而是 Navicat 连接属性里没启用 Unicode。PostgreSQL 默认用 UTF8,但 Navicat 若以非 Unicode 模式连接,读取 pg_description 表里的 description 字段就会解码失败,显示为空或乱码符号(如 )。
- 右键连接 →「编辑连接」→「高级」选项卡 → 勾选
Use Unicode - 确保源库和目标库的
client_encoding都是utf8(执行SHOW client_encoding;确认) - 若模型来自逆向工程,两次导出时源库的
information_schema字符集必须一致;否则字段注释被截断,Navicat 会误判为“描述变更”而非“无变化”
public.users 和 app.users 当作等价对象处理,也不会把 user_id 和 uid 当作可映射字段。这些都得靠你提前在连接设置、schema 映射或对象过滤里收口。











