如何在生产系统上实际重命名 PostgreSQL 中的表和列?

Lau*_*ves 14 postgresql

经常发生的情况是,最初的名称并不是最好的名称。也许需求略有变化,或者随着时间的推移,对所代表的概念有了更好的理解。有时在开发一项功能时会使用一个名称,但对真实用户的测试表明需要一个更好的名称,并且最好让数据库中的事物名称与 UI 中使用的名称相匹配。

PostgreSQL 允许您通过以下方式重命名表和列alter table,但通常这在没有大量停机时间的生产中是不可行的。如果现有客户正在使用旧名称,您不能只是将其从他们的名称中删除。

我希望有某种方法可以向表或列“添加名称”,这样old_namenew_name都可以工作,然后稍后删除旧名称。然后名称迁移可以像这样工作:

  • 添加new_name
  • 修改所有客户端以使用new_name而不是old_name
  • 更新所有客户端后,删除old_name

有没有办法做到这一点?如果没有,是否有推荐的程序来重命名色谱柱,同时最大限度地减少停机时间?一张桌子怎么样?

Lau*_*ves 15

一些在生产系统中重命名表和/或列的方法似乎有效。但是,我只在小型测试数据库上测试了这些,而不是在大型生产系统上。不过,重命名和视图创建都应该非常快。

重命名表

  1. 重命名该表,并临时添加一个具有旧名称的可更新视图:

    begin;
        alter table old_table_name rename to new_table_name;
    
        create view old_table_name as
            select * from new_table_name;
    commit;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 迁移客户端以使用新的表名称。

  3. 迁移所有客户端后,删除视图:

    drop view old_table_name;
    
    Run Code Online (Sandbox Code Playgroud)

重命名列而不重命名表

重命名列而不重命名表有点复杂,因为我们不能让视图隐藏表(显然)。

  1. 重命名列,临时重命名表,并添加一个可更新视图,该视图使用表的正确名称添加列的旧名称:

    begin;
        alter table my_table rename column old_column_name to new_column_name;
    
        alter table my_table rename to my_table_tmp;
    
        create view my_table as
            select *, new_column_name as old_column_name
            from my_table_tmp;
    
    commit;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 迁移客户端以使用新的列名称。

  3. 迁移所有客户端后,删除视图,将表重命名回来:

    begin;
        drop view my_table;
    
        alter table my_table_tmp rename to my_table;
    commit;
    
    Run Code Online (Sandbox Code Playgroud)

同时重命名表及其某些列

  1. 重命名表和列,并临时添加具有旧名称和旧列的可更新视图:

    begin;
        alter table old_table_name
            rename to new_table_name;
    
        alter table new_table_name
            rename column old_column_name to new_column_name;
    
        create view old_table_name as
            select *, old_column_name as new_column_name
            from new_table_name;
    commit;
    
    Run Code Online (Sandbox Code Playgroud)

    select *, old_column_name as new_column_name最好只拥有原始的列集,而不是,因此客户端必须迁移到新的表名才能获取新的列名:

    create view old_table_name as
        select
            unchanged_name1,
            unchanged_name2,
            ...
            old_column_name as new_column_name
        from new_table_name;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 迁移客户端以使用新的表名和列名。

  3. 迁移所有客户端后,删除视图:

    drop view old_table_name;
    
    Run Code Online (Sandbox Code Playgroud)

  • @Tvaroh 删除一列要简单得多。1. 更改所有客户端停止读取。2. 使该列可为空或为其指定一个默认值(如果还没有)。3. 将所有客户端更改为不再写入。4. 删除列:`alter table table_name drop column column_name`。 (2认同)