结构同步不能仅靠create table as select或show create table,须拆解为字段、索引、约束三类元数据逐项比对,生成安全alter语句,并处理跨库类型映射、权限及环境兼容性问题。

能同步,但不能只靠 CREATE TABLE ... AS SELECT 一类语句一劳永逸 —— 表结构变更包含字段增删改、索引、约束、默认值、字符集等,必须逐项比对生成 DDL。
为什么直接用 SHOW CREATE TABLE 同步会出错
从源库执行 SHOW CREATE TABLE 拿到建表语句,再在目标库执行,看似简单,实则埋雷:
- 目标库可能已存在同名表,直接执行会报
ERROR 1050 (42S01): Table 'xxx' already exists - 语句中带
AUTO_INCREMENT值或ENGINE=InnoDB DEFAULT CHARSET=utf8mb4等环境相关参数,目标库不兼容(比如 MySQL 5.7 vs 8.0 字符集默认行为不同) - 忽略外键约束、触发器、分区定义等非核心但关键的结构项
- 无法识别“字段类型微调”,比如
VARCHAR(100)→VARCHAR(255)是兼容变更,但INT→TINYINT可能丢数据,需人工确认
用 information_schema 获取字段级差异
真正可控的同步起点是把表结构拆成字段、索引、约束三类元数据,分别比对。核心查询如下:
SELECT column_name, data_type, character_maximum_length, is_nullable, column_default, extra FROM information_schema.columns WHERE table_schema = 'source_db' AND table_name = 'user_profile'
对比时注意:
-
column_default值可能为NULL或字符串'CURRENT_TIMESTAMP',需去除引号再比较 -
extra字段含auto_increment,但 MySQL 8.0+ 还可能返回STORED GENERATED,不能简单用==判定 - 目标库若为 PostgreSQL,
information_schema字段名和返回值格式不同(如data_type返回character varying而非varchar),需做映射转换
生成可安全执行的 ALTER 语句而非重建表
结构同步的本质不是“重装”,而是“增量修正”。应优先生成 ALTER TABLE,仅当变更不可逆(如删主键、改列类型导致数据截断)时才提示人工介入:
- 新增字段:用
ALTER TABLE t ADD COLUMN c VARCHAR(50) NOT NULL DEFAULT '' - 修改字段类型:先检查该列是否为空,再用
MODIFY COLUMN或CHANGE COLUMN(注意 MySQL 中二者语法差异) - 删字段:必须确认目标表无业务写入,且上游已下线依赖该字段的代码
- 加索引:用
ADD INDEX idx_name (col1, col2),避免在大表上阻塞写入;可加ALGORITHM=INPLACE(MySQL 5.6+)降低影响
跨数据库类型同步要放弃“自动推导”,明确映射规则
MySQL 的 TINYINT(1) 常被 ORM 当作布尔用,PostgreSQL 对应的是 BOOLEAN;MySQL 的 DATETIME 和 PostgreSQL 的 TIMESTAMP WITHOUT TIME ZONE 在时区处理上逻辑不同。这类差异无法靠脚本自动判断:
- 必须维护一份
type_mapping.yml配置,例如:mysql.tinyint: pg.boolean、mysql.json: pg.jsonb - 遇到未定义映射的类型(如 MySQL 的
ENUM),脚本应中断并报错Unsupported type: ENUM('a','b'),而不是强行转成VARCHAR - 主键策略差异(MySQL 自增 vs PG 序列)需单独处理,不能依赖
information_schema的column_key字段
结构同步最易被忽略的点是权限与上下文:DDL 执行用户必须有 ALTER 权限,而不仅仅是 SELECT;生产库往往禁用 ALTER TABLE ... ALGORITHM=COPY,这些限制不会出现在元数据里,只能靠配置或运行前校验。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











