我的目标是让数据库受版本控制,所以我一直在阅读文章,如Scott Allen’s series和许多老的SO相关的问题.但是我仍然无法决定如何进行.
我在想的是在一个文件中脚本化数据库模式,然后在一个文件中对程序,触发器和视图进行脚本化.然后将所有版本保留在Mercurial下.但是,当然,团队的每个成员都可以访问SSMS并直接更改模式和过程,我们可能会忘记在版本化文件中复制这些更改.
有什么更好的选择?而且,我忘了任何值得拥有源代码的元素吗?我最担心的是,我发现的大多数文献解释了在创建新数据库时如何进行版本控制,但是当它已经是旧的并且相对较大时.
解决方法
我们创建一个特定版本的基准(比如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表,它有两列:baseline和version.基准是一些标签(例如上面提到的v1.0),版本只是创建更改脚本时的时间戳(我们选择这样做是因为创建了任意版本号,创建了烦人的管理开销,时间戳很容易使用).因此,在运行更改脚本之前,我们检查更改脚本是否已被应用,通过基线和版本进行查询.如果已经存在,只需退出脚本或其他任何操作.否则,应用更改并插入到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)
现在,当我们实际安装软件时,我们运行相关的基准脚本.当我们升级该版本,我们只是按顺序应用更改脚本.
当我们在产品开发阶段达到重要的里程碑时,我们创造了一个新的基准.因此,我们创建一个新的基准脚本(再次,这是作为基准的数据库的快照),以及上一个基准线的升级脚本.所以假设我们有一个新的基线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工具直接升级生产数据库.这太冒险了当然,我们使用差异工具来帮助创建升级和更改脚本,但是一旦我们得到它们,我们梳理它们,按摩它们,测试它们,然后根据上面的规范创建升级或改变脚本.我们使用工具/ shell脚本创建更改脚本文件,并放置锅炉模式__version检查.
注意事项
它实际上很直观,效果很好.唯一的时间真的很棘手,是分支机构.在大多数情况下,分支机构处理得很好.如果我们需要一个特定分支工作的变更脚本,那么一旦我们合并了分支,它就会折叠到主线上.没问题.当两个分支尝试做类似的事情,或者一个分支依赖另一个分支时,它变得棘手.这主要是一个过程和规划问题.如果我们遇到这样的情况,我们只需创建一个新的基线(比如说v2.1),然后相应地更新分支.
要记住的另一件事是,如果安装需要从一个基准升级到另一个基准,则在升级到新基准之前,必须对当前基准线应用所有未完成的更改.换句话说,我们不允许安装从任何地方跳到下一个基准线(除非当然,它们已经是当前基准的最新版本).