数据库结构和源代码pipe理 – 最佳实践

背景

我来自在一家公司工作数年,所有数据库对象都存储在源代码pipe理中,每个对象一个文件。 当添加新项目时(为了让我们能够按顺序运行脚本并处理依赖性),我们有一个所有维护的对象的列表,还有一个VB脚本,用来创build一个用于运行数据库的大脚本。

所有的表格都是“如果不存在就创build”,所有的SP等都被删除并重新创build。

到目前为止,我现在正在一个数据库是主数据库的地方工作,没有数据库对象的源代码控制,但是我们使用redgate的工具来更新我们的生产数据库(SQL比较),这非常方便,需要很less的工作。

你如何处理你的数据库对象? 我喜欢让它们在源代码控制之下(而且,因为我们使用的是GIT,所以我希望能够处理脚本中的合并冲突,而不是DB),但是我会被迫使用SQL比较的难易程度来更新数据库。

我真的不想让我们更新GIT中的脚本,然后使用SQL比较来更新我们的DEV DB中的生产数据库,因为我宁愿拥有“真相的一个版本”,但我并不想重新编写一个自定义的软件来将所有的脚本捆绑在一起。

我认为,视觉工作室数据库版本可能会做类似的事情,但我不知道我们是否有预算。

我敢肯定,这已被要求死亡,但我找不到任何似乎有我正在寻找的答案。 与此类似,但不完全相同:

代码控制下的数据库脚本的最佳实践是什么?


开始一个赏金,因为我有兴趣在拉票多一些意见 – 这里的答案是健全的,但我觉得应该有一个更简单的方法。

感谢所有伟大的答案 – 都有其优点,所以我要拿最高票数,但欢呼所有的投入。

我们拥有使用Visual Studio数据库版本(DBPro)进行源代码pipe理的所有数据库对象。 它是版本控制我们的模式,构build,validation,允许代码分析,模式比较,部署,数据比较,重构等的一个奇妙的工具。它从头devise成为一个数据库pipe理和版本控制系统。 强烈推荐。

这是DBPro首席架构师的博客网站: http://blogs.msdn.com/gertd/archive/2008/11/25/visual-studio-team-system-2008-database-edition-gdr-rtm.aspx : http://blogs.msdn.com/gertd/archive/2008/11/25/visual-studio-team-system-2008-database-edition-gdr-rtm.aspx

看看这个关于数据库版本控制原理和实践的系列文章(由K. Scott Allen编写):

  1. 数据库工作的三条规则
  2. 基线
  3. 更改脚本
  4. 意见,stored procedures等等
  5. 分支和合并

这五个部分是重要的,但基本上是有一个基准,然后改变脚本(与版本表)。 更新数据库意味着在当前版本的“上方”应用更改脚本。 而且这个策略非常适合VCS(没有冲突)。

如果您已经在使用Red Gate工具,则可以考虑使用SQL Source Control,它与SQL Compare和SQL Data Compare一起使用,以便在源代码控制中存在一个真相版本。 目前在早期的访问,但大部分的function是在那里试用。 您可以从http://www.red-gate.com/Products/SQL_Source_Control/index.htm下载。; 但是,目前它只支持SVN和TFS。 你有没有在GIT上进行标准化?

大卫(红门产品经理)

假设您使用.net框架,请查看Fluent Migrator以及讨论该项目的“ 听闻代码”Podcast 。
我所看到的主要目标是在使用数据库不可知的方法使用stream畅接口进行常规编码时,轻松编写迁移代码。

它build立在.net框架之上。 并与许多数据库格式一起使用,包括SQL Server,SqlLite和MySQL。

这种方法的优点是它与您的其他代码一起生活,因此可以由SCMpipe理

例:

  [Migration(1)] public class CreateProjectsTable : Migration { public void Up() { Create.Table("Projects") .WithIdColumn() .WithColumn("Name").AsString().NotNullable() .WithColumn("Position").AsInt32().NotNullable() .WithColumn("Done").AsBoolean().NotNullable(); } public void Down() { Database.RemoveTable("Projects"); } } 

我们有一个系统,数据库名义上是主控制器,在我们的源代码控制系统中,我们维护着一系列的“模式更改”脚本(.sql文件),每个脚本负责ide然回滚更改并应用它。 每个脚本都只是编号,所以我们有000.sql(创build数据库和设置标准对象),001.sql等

在开发过程中,开发人员编写模式更改脚本并在开发数据库中运行它。 每个更改都需要在dba.change_info表中添加一行,其中包含更改编号和简要描述。 为了回滚更改,可以运行第一部分。 对于SQL Server来说,在发出DROP命令之前,通过检查sysobjects等来处理回滚部分的幂等性 – 类似于“drop … if exists”结构。 如果模型正在被改变而不是简单地被添加,模式改变可能需要进行数据的迁移,并且还被用于维护参考数据。

在发布过程中,DBA(我们是一个小公司,所以这是一个开发人员承担的angular色)将发布的模式更改应用到生产数据库,停止旧版本的应用程序和启动更新的。

这完全是一个手动过程,但满足了将数据从一个模型迁移到另一个模型的需求:例如将布尔标志扩展为一组选项,或将多对一关联转换为多对多关系。 这通常不是简单的模式比较工具就可以生成的东西。 它还允许angular色分离 – 尽pipe实际上我们都有完全的生产访问权限,但是在那里有足够的解耦,以便“DBA”可以读取和审查要在生产中应用的.sql文件。

理论上,至less,一个完整的数据库(只包含参考数据)可以通过简单地运行所有的schema变化来构build000.sql。 在实践中,我们不经常这样做,而是将我们的生产数据库复制到dev,然后在发布之前运行回归testing之前应用更改脚本。 这用于testing更改脚本本身,但仅适用于中等大小的生产数据库。

我对RedGate工具箱不是很熟悉,但是如果它与dbGhost类似,必须有一个实用程序,允许您将数据库对象脚本编写为每个对象一个文件。 在这种情况下,我会build议如下:

  • 添加每日(或部分构build)作业来将DEV数据库反向工程到目录结构中
  • 然后将其与存储库中的内容(通过简单的差异)进行比较,基本上会失败构build作业并报告diff如果有)。 这将表明DEV数据库的结构已经改变,并且不会反映在源代码pipe理中,
  • 这将指示开发人员将更改添加到源代码pipe理(甚至使用报告的.diff文件)

如果你有很多的DEV数据库(每个用户或者开发分支),而且太麻烦了,那么在数据库的STAGE (刚刚发布之前的版本)版本上做一个更好的组合就可能是一个更好的组合,存储库中的PROD模式,并且只会在预发布testing阶段从STAGE进行更新,您将确保模式更改也在存储库中。

这样开发人员仍然可以以通常的方式工作:首先更改DEV数据库上的模式,并希望在flexibility和您想要的one truth之间取得平衡。

在我们的团队中,只要更改DEV数据库,就会将更改添加到VCS,但是我们仍然有这样的任务来比较不同数据库(DEV,STAGE和PROD)之间的模式。 基本上,我们遵循我曾经回答过的问题如何从源代码pipe理构build数据库? 。

我目前在一个build模工具(DeZine for Databases)中维护数据库devise,并将其存储在源代码控制之下。 在我的表格devise中,我添加了一个包含两个行的表格,这两个表格具有架构的版本号和引用数据,每次更改/释放数据库(用户不访问此表)时都会更新。

参考数据保存在Excel电子表格中(也在源代码pipe理下),可以生成一个INSERT语句的SQL脚本来填充新的数据库。

当需要新版本时,模式脚本,引用数据脚本和安装程序包将被发送出去。 安装程序包重新命名旧的数据库,从脚本创build一个新的数据库,并导入新的参考数据(也可能已经更改)。 用户的数据然后从旧的(重新命名的)数据库复制到新的。

这有一个好处,当出现问题时,您可以恢复到原来的数据库,因为它没有被修改。

这个确切的东西有一个特殊的工具。 它被称为Wizardby :

数据库持续集成和模式迁移框架

Wizardby工作stream程http://octalforty-wizardby.googlecode.com/svn/trunk/docs/img/database_versioning_with_wizardby.png

在工作中,我们大量使用了一个强大的工具,它是ActiveRecord的一部分(这是默认的ORM,与Rails web框架一起被称为Migrations 。

基本的迁移将如下所示:

 class AddSystems < ActiveRecord::Migration def self.up create_table :systems do |t| t.string :name t.string :label t.text :value t.string :type t.integer :position, :default => 1 t.timestamps end end def self.down drop_table :systems end end 

为每个数据库更改都创build了一个迁移,并按照时间戳顺序创build它们。 您可以运行预定义的方法以正确的顺序运行这些迁移,以便始终创build和/或回滚数据库。 一些function如下:

 rake db:migrate #run all outstanding migrations rake db:rollback #roll back the last run migration rake db:seed #fill the database with your seed data 

迁移有创build表,删除表,更新表,添加索引等方法。完整的套件。 迁移还会自动添加一个id列,而t.timestamps节自动生成一个“created_at”字段和一个“updated_at”字段。

大多数语言都具有这样的ORMfunction,它们允许数据库以类似代码的状态进行维护,这对开发人员来说很容易理解,并且对于DBA的使用和维护来说足够简单。