在不停机的情况下重命名现有列

Posted

技术标签:

【中文标题】在不停机的情况下重命名现有列【英文标题】:Renaming an existing column without downtime 【发布时间】:2017-01-19 17:08:35 【问题描述】:

我想重命名表中的列。我看到了两种方法

    使用sp_rename() 并修改存储过程以引用新名称。

    创建新列,将数据从旧列复制到新列,修改存储过程等以引用新列,最终删除旧列。

我们不能使用 #1 作为重命名列可能会导致存储过程中断,我们无法承受任何停机时间。 如果我们使用 #2,则在数据从旧列复制到新列之后但在部署存储过程以使用新列之前,旧列和新列可能会共存一段时间。

有什么方法可以使新列与对旧列所做的任何更新/插入/删除保持同步?

    AFTER 触发器可以在这里提供帮助吗?但触发器通常会增加交易时间,因此可能不是一个有利的解决方案。 我可以在同一个表的两列之间复制数据吗? 还有其他可能的解决方案吗?

sp_rename() 是否也干净地更新了对列的所有引用——比如存储过程、函数、索引等?

【问题讨论】:

sp_rename() 是否干净地更新了对列的所有引用? - 好像不是,Renaming a column in MS SQL Server 2005 不,sp_rename 不会更改任何引用该列的对象——但安装过程应该只需要几秒钟。我真的不明白你怎么能更快地做到这一点......如果你不能做到这一点,你将如何维护你的数据库? 可能有任何应用程序受到影响?有动态的 SQL 吗? @JamesZ 我们主要分多个步骤进行部署,并通过这种方式确保两个步骤之间的向后兼容性 1) 客户不会注意到由于部署而导致的任何停机时间 2) 我们可以轻松回滚并且只有最后一次更改 3)如果现有功能出现任何问题,我们可以推迟进一步部署。这意味着我们无法保证能够在几秒钟内部署修改后的程序。 对我来说,这听起来你只是通过尝试多个步骤来使其过于复杂。如果您只是将列重命名 + 安装过程作为一个步骤,那么一切都应该工作,如果没有,则重命名 + 安装旧版本 - 比尝试提出某种数据复制/复制要简单得多。 【参考方案1】:

首先确认没有从数据库外部引用该列,例如应用程序代码直接查询该列而不通过存储过程。

这是我在不导致停机的情况下重命名列的方法 -

    在现有列之外添加一个新列。新列的数据类型与旧列相同,但名称不同。还可以根据用例在新列上创建索引、修改复制等。 修改所有写入(插入/更新操作)到旧列的存储过程,以便在新列中也插入/更新。 将旧列的数据复制到现有记录的新列。现在将第 2 步和第 3 步一起确保新列与旧列保持同步。 将从旧列读取的所有存储过程修改为现在从新列读取。

现在所有代码都已转换为使用新列,我们需要清理 -

    修改前面第 2 步中的存储过程以停止引用旧列。 删除旧列。

【讨论】:

【参考方案2】:

您可以重命名表并使用旧表名创建视图,并让视图包含列的别名。


SQLPrompt by redgate 有一个名为 Smart Rename 的功能,它可以重命名列并将所有引用更新为新名称。

来自 SQL Prompt 7 文档:

SQL Prompt 可以创建一个脚本,允许您在不破坏依赖关系的情况下重命名数据库中的对象。您可以重命名以下内容:

表格(包括列)

视图(包括列)

存储过程(包括参数)

函数(包括参数)

重命名对象时:

SQL Prompt 还会修改任何引用重命名对象或被重命名对象引用的对象,以确保依赖关系链接不会中断。

如果您之前使用 SQL Server Management Studio 或 Enterprise Manager Rename 或 T-SQL sp_rename 命令重命名了对象,则对象定义将包含原始名称。

任何引用此原始名称的对象都不会更新。

为了帮助您找到引用不再存在的对象的对象,请参阅查找无效对象。

保留对象的原始权限和扩展属性。

【讨论】:

以上是关于在不停机的情况下重命名现有列的主要内容,如果未能解决你的问题,请参考以下文章

使用ant,在不知道完整路径的情况下重命名目录?

如何在不删除或移动mysql中的表的情况下重命名数据库? [复制]

如何在不破坏 Subversion 历史的情况下重命名 Java 包?

如何在不破坏文件的情况下重命名xcode项目中的文件夹名称

数据透视表列重命名

重命名 node.js 续集时间戳列