SQL版本控制方法

发布于 2024-08-31 18:51:39 字数 895 浏览 4 评论 0 原文

SO 有几个关于 SQL 版本控制的问题,网上有很多资源,但我找不到完全涵盖我想要做的事情的东西。

首先,我在这里谈论一个方法论。我熟悉各种源代码控制应用程序,也熟悉 Red Gate 的 SQL Compare 等工具,并且我知道如何编写应用程序来自动将内容签入和签出我的源代码控制系统。如果有一个工具对于提供全新的方法特别有帮助,或者具有有用且不常见的功能,那就太好了,但是对于上面提到的任务,我已经设置好了。

我试图满足的要求是:

  • 数据库模式和查找表数据是版本化的
  • 用于对较大表进行数据修复的 DML 脚本是版本化的
  • 服务器可以从版本 N 升级到版本 N + X,其中 X 可能并不总是如此be 1
  • 代码在版本控制系统中不会重复 - 例如,如果我向表中添加一列,我不想确保更改同时存在于创建脚本和更改脚本中
  • 系统需要支持应用程序处于不同版本的多个客户端(试图将它们全部提升到 1 或 2 个版本内,但尚未实现)

一些组织在其版本控制中保留增量更改脚本,并从版本 N 升级到 N + 3 您必须运行 N->N+1、N+1->N+2、N+2->N+3 的脚本。其中一些脚本可能是重复的(例如,添加了一列,但随后对其进行了更改以更改数据类型)。我们正在努力避免这种重复,因为某些客户端数据库可能非常大,因此这些更改可能需要比必要的时间更长的时间。

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

也许有一些混合解决方案?也许我只是要求太多?任何想法或建议将不胜感激。

如果版主认为这作为社区 wiki 更合适,请告诉我。

谢谢!

There are several questions on SO about version control for SQL and lots of resources on the web, but I can't find something that quite covers what I'm trying to do.

First off, I'm talking about a methodology here. I'm familiar with the various source control applications out there and I'm familiar with tools like Red Gate's SQL Compare, etc. and I know how to write an application to check things in and out of my source control system automatically. If there is a tool which would be particularly helpful in providing a whole new methodology or which have a useful and uncommon functionality then great, but for the tasks mentioned above I'm already set.

The requirements that I'm trying to meet are:

  • The database schema and look-up table data are versioned
  • DML scripts for data fixes to larger tables are versioned
  • A server can be promoted from version N to version N + X where X may not always be 1
  • Code isn't duplicated within the version control system - for example, if I add a column to a table I don't want to have to make sure that the change is in both a create script and an alter script
  • The system needs to support multiple clients who are at various versions for the application (trying to get them all up to within 1 or 2 releases, but not there yet)

Some organizations keep incremental change scripts in their version control and to get from version N to N + 3 you would have to run scripts for N->N+1 then N+1->N+2 then N+2->N+3. Some of these scripts can be repetitive (for example, a column is added but then later it is altered to change the data type). We're trying to avoid that repetitiveness since some of the client DBs can be very large, so these changes might take longer than necessary.

Some organizations will simply keep a full database build script at each version level then use a tool like SQL Compare to bring a database up to one of those versions. The problem here is that intermixing DML scripts can be a problem. Imagine a scenario where I add a column, use a DML script to fill said column, then in a later version that column name is changed.

Perhaps there is some hybrid solution? Maybe I'm just asking for too much? Any ideas or suggestions would be greatly appreciated though.

If the moderators think that this would be more appropriate as a community wiki, please let me know.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

回心转意 2024-09-07 18:51:39

我在这个问题上挣扎了好几年,直到最近采用了一种似乎效果很好的策略。我坚持的要点:

  • 数据库不需要独立于应用程序进行版本控制
  • 所有数据库更新脚本都应该是幂等

的 因此,我不再创建任何类型的版本表。我只是将更改添加到 .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 等...

在任何给定时间,我都可以在任何状态下针对数据库运行整个系列的脚本,并且知道事情会立即发生跟上应用程序的当前版本。因为一切都是脚本化的,所以构建一个简单的安装程序来执行此操作要容易得多,并且将架构更改添加到源代码管理完全没有问题。

I struggled with this for several years before recently adopting a strategy that seems to work pretty well. Key points I live by:

  • The database doesn't need to be independently versioned from the app
  • All database update scripts should be idempotent

As a result, I no longer create any kind of version tables. I simply add changes to a numbered sequence of .sql files that can be applied at any given time without corrupting the database. If it makes things easier, I'll write a simple installer screen for the app to allow administrators to run these scripts whenever they like.

Of course, this method does impose a few requirements on the database design:

  • All schema changes are done through script - no GUI work.
  • Extra care must be taken to ensure all keys, constraints, etc.. are named so they can be referenced by a later update script, if necessary.
  • All update scripts should check for existing conditions.

Examples from a recent project:

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, etc...

At any given time I can run the entire series of scripts against the database in any state and know that things will be immediately brought up to speed with the current version of the app. Because everything is scripted, it's much easier to build a simple installer to do this, and it's adding the schema changes to source control is no problem at all.

何以笙箫默 2024-09-07 18:51:39

你有一套相当严格的要求,我不确定你是否会找到一些可以满足所有条件的东西,特别是多个并发模式和智能版本控制。

我读过的关于这种适合的最有前途的工具是 Liquibase
以下是一些其他链接:

  • http://en.wikipedia.org/wiki/LiquiBase
  • < a href="http://www.ibm.com/developerworks/java/library/j-ap08058/index.html" rel="nofollow noreferrer">http://www.ibm.com/developerworks/java/library /j-ap08058/index.html

You've got quite a rigorous set of requirements, I'm not sure whether you'll find something that puts checks in all the boxes, especially the multiple concurrent schemas and the intelligent version control.

The most promising tool that I've read about that kind of fits is Liquibase.
Here are some additional links:

你的呼吸 2024-09-07 18:51:39

是的,您要求很多,但它们都是非常相关的要点!在 Red Gate,我们正在通过 SQL 源代码控制 SSMS 扩展转向完整的数据库开发解决方案,我们也面临着类似的挑战。

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

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

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

Yes, you're asking for a lot, but they're all really pertinent points! Here at Red Gate we're moving towards a complete database development solution with our SQL Source Control SSMS extension and we're facing similar challenges.

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

For the upcoming release we're fully supporting schema changes, and supporting static data indirectly via our SQL Data Compare tool. All changes are saved as creation scripts, although when you're updating or deploying to a database, the tool will ensure that the changes are applied appropriately as an ALTER or CREATE.

The most challenging requirement that doesn't yet have a simple solution is version management and deployment, which you describe very clearly. If you make complex changes to the schema and data, it may be inevitable that a handcrafted migration script is constructed to get between two adjacent versions, as not all of the 'intent' is always saved alongside a newer version. Column renames are a prime example. The solution could be for a system to be devised that saves the intent, or if this is too complex, allows the user to supply a custom script to perform the complex change. Some sort of version management framework would manage these and "magically" construct deployment scripts from two arbitrary versions.

尹雨沫 2024-09-07 18:51:39

对于此类问题,请使用Visual studio team system 2008对sql数据库进行版本控制。

在 tsf 中没有。 的功能

  • 像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

for this kind of issue use Visual studio team system 2008 for version controlling of your sql database.

In tsf there are no. of feature avialbe like

  • Datacompare
  • Schemacompare
  • version controlling

about database version control : http://www.codinghorror.com/blog/2006/12/is-your-database-under-version-control.html
for more detail check : http://msdn.microsoft.com/en-us/library/ms364062(VS.80).aspx

如此安好 2024-09-07 18:51:39

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

以下是 SQL Examiner 方法的描述:如何将数据库置于版本控制之下

We are using SQL Examiner for keeping database schema under version control. I've tried the VS2010 also, but in my opinion VS approach is too complex for small and mid-size projects. With SQL Examiner I mostly work with SSMS and use SQL Examiner to check-in updates to SVN (TFS and SourceSafe is supported also, but I never tried it).

Here is description of SQL Examiner's approach: How to get your database under version control

追星践月 2024-09-07 18:51:39

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

Try DBSourceTools. (http://dbsourcetools.codeplex.com)
Its open source, and specifically designed to script an entire database - tables, views, procs to disk, and then re-create that database through a deployment target.
You can script all data, or just specify which tables to script data for.
Additionally, you can zip up the results for distribution.
We use it for source control of databases, and to test update patches for new releases.
In the back-end it's built around SMO, and thus supports SQL 2000, 2005 and 2008.
DBDiff is integrated, to allow for schema comparisons.
Have fun,
- Nathan.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文