将版本控件添加到现有的SQL Server数据库中



我是当前使用没有任何源控制的数据库的开发团队的一部分。我们与SQL Server 2008 R2合作,并始终使用SSM直接管理DB。现在它具有〜340个表和〜1600个存储过程,以及一些触发器和视图,因此不是小db。

我的目标是让DB在版本中控制,因此我一直在阅读文章,例如Scott Allen的系列和许多相关的问题。但是我仍然无法决定如何进行。

我想的是在一个文件中脚本脚本脚本数据库架构,然后在一个文件中触发和视图。然后将所有内容保留在Mercurial下。但是,当然,团队中的每个成员都可以访问SSM并直接更改架构和过程,因此我们任何人都可以忘记在版本的文件中复制这些更改。

有哪些更好的选择?而且,我是否忘记了任何值得对来源控制的元素?我最大的担忧是,我发现的大多数文献都解释了在创建新数据库时如何进行版本控制的方法,而不是在旧数据库中且相对较大。

常规过程

我们为特定版本创建一个基线(例如v1.0)。基线包括一个完整的架构创建脚本,以及从允许的先前版本(如果有的话)的升级脚本。因此,对于v1.0,我们只有一个脚本:

baseline-v1.0.sql

从该基线开始,我们从上一个基线工作时创建增量更改脚本。这些脚本的创建方式是它们是重新进入的方式,以便可以安全地运行多次(其中首次仅进行任何实际工作;请参阅建议的下一段)。我们只需使用基线名称和一个时间戳(我们称为版本)为每个更改脚本创建一个文件。因此,例如,假设我们在基线后创建两个更改脚本。我们将有以下文件:

baseline-v1.0.sql (for creating new installations)
baseline-v1.0-201211071220.sql (created on Nov. 7, 2012 at 12:20 PM UTC)
baseline-v1.0-201211122019.sql (created on Nov. 12, 2012 at 8:00 PM UTC)

我们创建一个具有两个列的schema_version表:baselineversionbaseline是一些标签(例如上面提到的v1.0),而version只是创建更改脚本的时间戳(我们之所以选择这样做,是因为创建任意的版本编号创建了烦人的管理高架开销,其中时间戳易于使用)。因此,在运行更改脚本之前,我们通过查询baselineversion查询是否应用了更改脚本。如果已经存在,只需返回脚本或其他内容即可。否则,将更改应用于schema_version表中以标记完成的更改脚本。

示例更改脚本:

-- Created by <developer> on Nov. 7, 2012 at 12:20 PM UTC
declare @schema_baseline varchar(10), @schema_version varchar(12)
set @schema_baseline = 'v1.0'
set @schema_version = '201211071210'
if exists (select 1 from schema_version where baseline = @schema_baseline and version = @schema_version = @schema_version) return 0
-- begin change script
-- place your schema changes here
-- end change script
insert into schema_version(@schema_baseline, @schema_version)

现在,当我们实际安装软件时,我们运行相关的baseline脚本。当我们升级该版本时,我们只需按顺序应用更改脚本。

当我们在产品开发阶段达到一个重要的里程碑时,我们会创建一个新的基线。因此,我们创建了一个新的基线脚本(同样,这是DB作为基线的快照),以及上一个基线的升级脚本。假设我们有一个新的基线v2.0,我们将有以下文件:

baseline-v2.0.sql (for creating new installations)
baseline-v2.0-upgrade-v1.0.sql (for upgrading from v1.0)

然后该过程继续。

我们如何应用更改

这些脚本都保存在源控制中。我们确实有一个包装这些文件并自动升级数据库的工具,我们的支持和安装团队使用这些数据库。该工具算出了目标数据库的当前基线,并询问用户是否希望升级到包装中的基线。如果他们这样做,并且有一个有效的升级路径,它将应用升级脚本并更新schema_version.baseline,并从上一个基线删除所有更改脚本的条目。如果数据库是新的,则应用常规基线脚本。无论哪种方式,在实现基线之后,它都会应用包装中存在的所有更改脚本。如果特定的更改脚本失败,它将倒退最后一组更改和错误。我们查看日志,解决任何问题,然后再次重新运行包。那时,它应该只在成功的最后一个更改脚本上拾取,节省了时间。

自动化和DIFF工具

我们不允许DIFF工具直接升级生产数据库。这太冒险了。当然,我们确实使用DIFF工具来帮助创建升级和更改脚本,但是一旦拥有它们,我们就会梳理它们,按摩它们,测试它们等,然后根据上面的规格创建升级或更改脚本。我们确实使用工具/外壳脚本来创建更改脚本文件并将锅炉板schema_version检查。

警告

它实际上很简单,效果很好。它真正遇到的唯一棘手是分支。在大多数情况下,分支机构的处理良好。如果我们需要一个特定分支工作的更改脚本,一旦我们将分支合并回去,它将非常好折叠到主线。没问题。棘手的地方是两个分支尝试做类似的事情,或者一个分支依赖另一个分支。但是,这主要是一个过程和计划问题。如果我们陷入这种情况,我们只会创建一个新的基线(例如v2.1),然后相应地更新分支。

要记住的另一件事是,如果安装想从一个基线升级到另一个基线,则必须对当前基线进行所有出色的更改,然后才能升级到新的基线。换句话说,我们不会让安装从他们的位置直接跳到下一个基线(当然,除非它们已经是当前基线的最新版本)。

我会建议SQL Server数据工具和/或Visual Studio SQL数据库项目。它将将您现有的DB逆转为可以控制版本的代码(SQL)文件,并提供许多其他nigities(发布,比较等)

我们专门开发了SQL源控制,以解决您描述的问题。它扩展了SSM,以提供SQL Server架构对象(和静态数据)与现有源控制系统之间的链接。

http://www.red-gate.com/products/sql-development/sql-source-control/

如果您需要更多信息,我们会很高兴为您提供帮助(联系support@red-gate.com)

许多开发人员论坛上有关此主题的许多讨论。

我所做的并发现最简单,最干净的方法是:

  1. 将每个DB对象的DDL提取到其自己的文件中,索引和PK可以与它们所属的表中的同一文件中。FKS,过程,视图,触发器,任何可以跨多个表都插入自己的文件的事物。

  2. 以每个对象类型的dirs组织DDL文件(例如表,过程,触发器,查看等)

  3. 对于持有静态参考数据的表(例如,邮政编码或状态),有一个带有一堆插入语句的文件

  4. 将此目录结构检查到您使用的任何版本控件中

  5. 编写一个脚本,该脚本将穿越此目录结构,该目录结构图像您的数据库,将其差异与您指向的实际db(从系统表中提取架构)并使用Alter表语句应用差异

  6. 如果您在发行版之间具有数据转换,例如在V1中,您有一个字段firstAndlastName,在V2中,您决定将其拆分为firstName和lastName,您将有一些批量的数据迁移/处理语句。

我使用几种不同的RDBMS成功地管理了多个作业的数据库更改。我通常将perl用于图像中分散DB模式和DDL文件的脚本。该方法有一些假设,其中之一是您永远不会直接在DB中对DB进行任何更改,而是在DDL文件中进行任何更改,然后运行脚本以应用它。如果您以其他方式进行操作,则在运行脚本时会撤消它们。因此,它需要一些团队协议和纪律。您的里程可能会有所不同。

现在,如果有一个FOSS工具可以为您执行此操作,那么一定要使用它而不是设计自己的。我一直在这样做10年以上的事情

我们的SQL历史学家源控制系统可以帮助人们解决这个问题,尤其是在您的情况下提及队友在更新服务器后"忘记"检查代码。

它位于背景中,并记录对DB对象所做的所有更改,而无需检查任何内容。将其视为飞机BlackBox录音机,直到需要它。

最新更新