V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
爱意满满的作品展示区。
KURANADO

写了个命令版的表结构差异对比工具(仅限于 MariaDB)

  •  
  •   KURANADO · Mar 7, 2025 · 1798 views
    This topic created in 424 days ago, the information mentioned may be changed or developed.

    项目上不同环境发版需要对比表结构差异,为此经常需要手动点击 Navicat 的表结构同步功能进行数据库比对,生成 create table 、drop table 、alter table 等语句

    为了自动化比对,封装了一个命令行版的对比工具,在 shell 脚本中调用,一键输出同步语句。

    例如初始情况下 a_chemab_schema 均有如下 ddl:

    create table user (
                          id bigint comment '主键',
                          name varchar(30) null comment '姓名',
                          address varchar(50) null comment '地址',
                          number varchar(20) null comment '编号',
                          height float null comment '身高'
    );
    
    create table teacher (
                             name varchar(30) null comment '姓名'
    );
    
    create index idx_name on user(name);
    
    create index idx_multiple_field on user(name, address);
    
    create table course (
                            id      bigint primary key auto_increment comment '主键',
                            name    varchar(30) null comment '课程名称',
                            teacher varchar(30) null comment '教师',
                            credit  float       null comment '学分'
    );
    
    create table pig (
                         id bigint not null comment '名称',
                         weight bigint not null comment '重量'
    );
    

    此时对 a_schema 做如下修改:

    use a_schema;
    alter table user modify column id bigint primary key auto_increment not null comment '主键';
    alter table user add column age int default 18 null comment '年龄';
    alter table user add column create_time datetime not null default current_timestamp comment '创建时间';
    alter table user modify column address varchar(100) not null default 'Shanghai' comment '地址';
    alter table user change column number phone varchar(20) null comment '电话号码';
    alter table user drop column height;
    alter table user add unique index uk_phone(phone);
    alter table user drop index idx_name;
    create table student(
                            id bigint primary key auto_increment comment '主键',
                            no varchar(30) null comment '学号',
                            name varchar(30) null comment '姓名'
    );
    create unique index uk_no on student(no);
    drop index idx_multiple_field on user;
    create index idx_multiple_field on user(name, phone);
    drop table course;
    alter table user add unique index uk_test(age, create_time);
    alter table student add index idx_name(name);
    alter table teacher add COLUMN `id` bigint NOT NULL primary key AUTO_INCREMENT COMMENT '主键' FIRST;
    alter table pig add unique index uk_id_weight(id, weight);
    alter table pig modify column id bigint not null primary key auto_increment comment '名称';
    

    执行命令将会对比表结构差异后输出同步语句:

    $ ddl-diff \
    --original-user root \
    --original-password 123456 \
    --original-host 127.0.0.1 \
    --original-schema a_schema \
    --target-user root \
    --target-password 123456 \
    --target-host 127.0.0.1 \
    --target-schema b_schema
    
    use b_schema;
    CREATE TABLE `student`(
                              `id` bigint(20) NOT NULL  PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
                              `no` varchar(30) NULL DEFAULT NULL  COMMENT '学号',
                              `name` varchar(30) NULL DEFAULT NULL  COMMENT '姓名',
                              INDEX `idx_name` (`name`) USING BTREE,
                              UNIQUE INDEX `uk_no` (`no`) USING BTREE);
    ALTER TABLE `user` DROP INDEX `idx_name`;
    ALTER TABLE `user` DROP INDEX `idx_multiple_field`;
    ALTER TABLE `user` ADD COLUMN `phone` varchar(20) NULL DEFAULT NULL  COMMENT '电话号码' AFTER `address`;
    ALTER TABLE `user` ADD COLUMN `age` int(11) NULL DEFAULT 18  COMMENT '年龄' AFTER `phone`;
    ALTER TABLE `user` ADD COLUMN `create_time` datetime NOT NULL DEFAULT current_timestamp()  COMMENT '创建时间' AFTER `age`;
    ALTER TABLE `user` MODIFY COLUMN `id` bigint(20) NOT NULL  PRIMARY KEY AUTO_INCREMENT COMMENT '主键' FIRST;
    ALTER TABLE `user` MODIFY COLUMN `address` varchar(100) NOT NULL DEFAULT 'Shanghai'  COMMENT '地址' AFTER `name`;
    ALTER TABLE `user` DROP COLUMN `height`;
    ALTER TABLE `user` DROP COLUMN `number`;
    ALTER TABLE `user` ADD INDEX `idx_multiple_field` (`name`,`phone`) USING BTREE;
    ALTER TABLE `user` ADD UNIQUE INDEX `uk_test` (`age`,`create_time`) USING BTREE;
    
    ALTER TABLE `user` ADD UNIQUE INDEX `uk_phone` (`phone`) USING BTREE;
    ALTER TABLE `pig` MODIFY COLUMN `id` bigint(20) NOT NULL  PRIMARY KEY AUTO_INCREMENT COMMENT '名称' FIRST;
    
    ALTER TABLE `pig` ADD UNIQUE INDEX `uk_id_weight` (`id`,`weight`) USING BTREE;
    ALTER TABLE `teacher` ADD COLUMN `id` bigint(20) NOT NULL  PRIMARY KEY AUTO_INCREMENT COMMENT '主键' FIRST;
    
    DROP TABLE IF EXISTS `course`;
    

    目前存在的缺点有:

    • 如果使用的是 MySQL 数据库,则无法正确区分 default 表达式中的普通字符串和 MySQL 内置函数(问题原因是 MySQL INFORMATION_SCHEMA.COLUMNS 中并未对字符串和函数做区分。一种解决方法是通过将 SHOW CREATE TABLE xxx 的返回结果解析成 AST ,sqlparser crate 就具有这种解析能力); MariaDB 无此问题。
    • 无法区分字段重命名的情况,只能输出先删除字段、后新增字段的 alter table 语句。这是因为 INFORMATION_SCHEMA.COLUMNS 没有存储字段 id 。Navicat 、DataGrip 等工具的表结构差异对比都有此问题,所以在执行返回的语句之前,请务必仔细确认之后再执行。如果有小伙伴知道如何解决该问题,欢迎跟帖讨论。

    源码地址:https://github.com/KURANADO2/ddl-diff

    2 replies    2025-03-07 18:40:03 +08:00
    jybox
        1
    jybox  
       Mar 7, 2025
    之前用过这个工具 https://www.skeema.io
    很适合在几个环境之间同步表结构
    KURANADO
        2
    KURANADO  
    OP
       Mar 7, 2025
    @jybox 好东西
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2694 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 10:14 · PVG 18:14 · LAX 03:14 · JFK 06:14
    ♥ Do have faith in what you're doing.