SQL版本控制方法

时间:2010-05-05 15:29:13

标签: sql version-control migration

关于SQL的版本控制和网络上的大量资源,有几个问题,但我找不到能够完全覆盖我想要做的事情。

首先,我在谈论一种方法论。我熟悉那里的各种源代码控制应用程序,我熟悉Red Gate的SQL Compare等工具,我知道如何编写一个应用程序来自动检查进出源代码管理系统的内容。如果有一个工具对提供一种全新的方法特别有用,或者有一个有用且不常见的功能那么好,但对于上面提到的任务,我已经设定了。

我想要满足的要求是:

  • 数据库架构和查找表数据已版本化
  • 用于修复较大表的数据的DML脚本已版本化
  • 服务器可以从版本N升级到版本N + X,其中X可能不总是1
  • 代码在版本控制系统中不重复 - 例如,如果我向表中添加一列,我不希望确保更改同时包含在创建脚本和更改脚本中
  • 系统需要支持多个适用于该应用程序版本的客户端(尝试将它们全部发布到1或2个版本中,但尚未发布)

有些组织在其版本控制中保留增量更改脚本,并从版本N到N + 3,您必须运行N→1 + N + 1然后N + 1> N + 2然后N +的脚本2→N + 3。其中一些脚本可能是重复的(例如,添加了一列,但稍后会更改它以更改数据类型)。我们试图避免这种重复性,因为某些客户端数据库可能非常大,因此这些更改可能需要的时间超过必要时间。

有些组织只会在每个版本级别保留一个完整的数据库构建脚本,然后使用SQL Compare等工具将数据库升级到其中一个版本。这里的问题是混合DML脚本可能是个问题。想象一下我添加一个列,使用DML脚本填充所述列,然后在更高版本中更改列名的情况。

也许有一些混合解决方案?也许我只是要求太多?不过,任何想法或建议都会受到高度赞赏。

如果主持人认为这更适合作为社区维基,请告诉我。

谢谢!

6 个答案:

答案 0 :(得分:6)

在最近采用似乎运作良好的策略之前,我已经挣扎了好几年。我住的要点:

  • 数据库不需要从应用程序中独立版本化
  • 所有数据库更新脚本都应该是幂等的

结果,我不再创建任何类型的版本表。我只是将更改添加到.sql文件的编号序列中,这些文件可以在任何给定时间应用而不会破坏数据库。如果它让事情变得更容易,我会为应用程序编写一个简单的安装程序屏幕,以便管理员可以随时运行这些脚本。

当然,这种方法确实对数据库设计提出了一些要求:

  • 所有架构更改都是通过脚本完成的 - 没有GUI工作。
  • 必须特别注意确保所有键,约束等都被命名,以便在必要时可以通过更新的脚本引用它们。
  • 所有更新脚本都应检查现有条件。

最近项目的例子:

001.sql:

if object_id(N'dbo.Registrations') is null 
begin
    create table dbo.Registrations
    (
        [Id]                    uniqueidentifier not null,
        [SourceA]               nvarchar(50)     null,
        [SourceB]               nvarchar(50)     null,
        [Title]                 nvarchar(50)     not null,
        [Occupation]            nvarchar(50)     not null,
        [EmailAddress]          nvarchar(100)    not null,
        [FirstName]             nvarchar(50)     not null,
        [LastName]              nvarchar(50)     not null,
        [ClinicName]            nvarchar(200)    not null,
        [ClinicAddress]         nvarchar(50)     not null,
        [ClinicCity]            nvarchar(50)     not null,
        [ClinicState]           nchar(2)         not null,
        [ClinicPostal]          nvarchar(10)     not null,
        [ClinicPhoneNumber]     nvarchar(10)     not null,
        [ClinicPhoneExtension]  nvarchar(10)     not null,
        [ClinicFaxNumber]       nvarchar(10)     not null,
        [NumberOfVets]          int              not null,  
        [IpAddress]             nvarchar(20)     not null,
        [MailOptIn]             bit              not null,
        [EmailOptIn]            bit              not null,
        [Created]               datetime         not null,
        [Modified]              datetime         not null,
        [Deleted]               datetime         null
    );
end

if not exists(select 1 from information_schema.table_constraints where constraint_name = 'pk_registrations')
    alter table dbo.Registrations add
        constraint pk_registrations primary key nonclustered (Id);

if not exists (select 1 from sysindexes where [name] = 'ix_registrations_created')
    create clustered index ix_registrations_created
        on dbo.Registrations(Created);

if not exists (select 1 from sysindexes where [name] = 'ix_registrations_email')
    create index ix_registrations_email
        on dbo.Registrations(EmailAddress);

if not exists (select 1 from sysindexes where [name] = 'ix_registrations_email')
    create index ix_registrations_name_and_clinic
        on dbo.Registrations (FirstName,
                              LastName,
                              ClinicName);

002.sql

/**********************************************************************
  The original schema allowed null for these columns, but we don't want
  that, so update existing nulls and change the columns to disallow 
  null values
 *********************************************************************/

update dbo.Registrations set SourceA = '' where SourceA is null;
update dbo.Registrations set SourceB = '' where SourceB is null;
alter table dbo.Registrations alter column SourceA nvarchar(50) not null;
alter table dbo.Registrations alter column SourceB nvarchar(50) not null;

/**********************************************************************
  The client wanted to modify the signup form to include a fax opt-in
 *********************************************************************/

if not exists 
(
    select 1 
      from information_schema.columns
     where table_schema = 'dbo'
       and table_name   = 'Registrations'
       and column_name  = 'FaxOptIn'
)
alter table dbo.Registrations 
    add FaxOptIn bit null 
        constraint df_registrations_faxoptin default 0;

003.sql,004.sql等......

在任何给定时间,我都可以在任何状态下针对数据库运行整个系列的脚本,并且知道应用程序的当前版本会立即加快速度。因为所有内容都是脚本化的,所以构建一个简单的安装程序来实现这一点要容易得多,并且将架构更改添加到源代码控制中完全没有问题。

答案 1 :(得分:3)

你有一套严格的要求,我不确定你是否会找到能够将检查放在所有方框中的东西,特别是多个并发模式和智能版本控制。

我读过的最有希望的工具是Liquibase 以下是一些其他链接:

答案 2 :(得分:2)

是的,你要求很多,但它们都是非常重要的一点!在Red Gate,我们正朝着一个完整的数据库开发解决方案转向我们的SQL Source Control SSMS扩展,我们正面临着类似的挑战。

http://www.red-gate.com/products/SQL_Source_Control/index.htm

对于即将发布的版本,我们完全支持架构更改,并通过我们的SQL数据比较工具间接支持静态数据。所有更改都保存为创建脚本,但是当您更新或部署到数据库时,该工具将确保更改作为ALTER或CREATE正确应用。

尚未拥有简单解决方案的最具挑战性的要求是版本管理和部署,您可以非常清楚地描述。如果对模式和数据进行复杂的更改,则可能不可避免地构建手工迁移脚本以获取两个相邻版本,因为并非所有“intent”始终与较新版本一起保存。列重命名是一个很好的例子。解决方案可以是设计用于保存意图的系统,或者如果这太复杂,则允许用户提供自定义脚本来执行复杂的更改。某种版本管理框架可以管理这些,并“神奇地”构建来自两个任意版本的部署脚本。

答案 3 :(得分:1)

对于此类问题

使用 Visual Studio团队系统2008 来控制您的sql数据库。

在tsf中没有。特色avialbe喜欢

  • Datacompare
  • Schemacompare
  • 版本控制

关于数据库版本控制:http://www.codinghorror.com/blog/2006/12/is-your-database-under-version-control.html 有关详细信息,请查看:http://msdn.microsoft.com/en-us/library/ms364062(VS.80).aspx

答案 4 :(得分:1)

我们正在使用SQL Examiner将数据库架构保持在版本控制之下。我也尝试过VS2010,但在我看来,VS方法对于中小型项目来说过于复杂。使用SQL Examiner,我主要使用SSMS并使用SQL Examiner来检查SVN的更新(也支持TFS和SourceSafe,但我从未尝试过)。

以下是SQL Examiner方法的说明:How to get your database under version control

答案 5 :(得分:0)

尝试DBSourceTools。 (http://dbsourcetools.codeplex.com
它的开源,专门用于编写整个数据库的脚本 - 表,视图,磁盘,然后通过部署目标重新创建该数据库。
您可以编写所有数据的脚本,或者只指定要为其编写数据的表。
此外,您可以压缩结果以进行分发 我们将它用于数据库的源代码控制,并测试新版本的更新补丁 在后端它是围绕SMO构建的,因此支持SQL 2000,2005和2008 DBDiff已集成,以便进行模式比较 玩得开心, - 内森。