SQL版本控制方法

Tom*_*m H 14 sql migration version-control

有关SQL的版本控制和Web上的大量资源的问题有几个问题,但我找不到能够完全覆盖我正在尝试做的事情.

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

我想要满足的要求是:

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

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

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

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

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

谢谢!

Chr*_*ris 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);
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

003.sql,004.sql等...

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