版本化SQL Server数据库

时间:2008-08-01 18:33:08

标签: sql-server database svn version-control

我想让我的数据库受版本控制。有没有人有任何建议或推荐的文章让我入门?

我总是希望在那里至少包含一些数据(如alumb所述:用户类型和管理员)。我还经常需要大量生成的测试数据来进行性能测量。

29 个答案:

答案 0 :(得分:173)

Martin Fowler写了我最喜欢的关于这个主题的文章http://martinfowler.com/articles/evodb.html。我选择不将模式转储放在版本控制下作为 alumb 和其他人建议,因为我想要一种简单的方法来升级我的生产数据库。

对于我将拥有单个生产数据库实例的Web应用程序,我使用两种技术:

数据库升级脚本

序列数据库升级脚本,其中包含将架构从版本N移动到N + 1所需的DDL。 (这些都在您的版本控制系统中。)_version_history_表,类似于

create table VersionHistory (
    Version int primary key,
    UpgradeStart datetime not null,
    UpgradeEnd datetime
    );
每次运行与新版本相对应的升级脚本时,

都会获得一个新条目。

这确保了很容易看到存在哪个版本的数据库模式,并且数据库升级脚本只运行一次。同样,这些是数据库转储。相反,每个脚本代表从一个版本移动到下一个版本所需的更改。它们是您应用于生产数据库以“升级”它的脚本。

开发人员沙盒同步

  1. 用于备份,清理和收缩生产数据库的脚本。每次升级到生产数据库后运行此项。
  2. 在开发人员的工作站上恢复(并在必要时调整)备份的脚本。每次开发人员在每次升级到生产数据库后都会运行此脚本。
  3. 警告:我的自动化测试针对架构正确但空的数据库运行,因此这个建议不能完全满足您的需求。

答案 1 :(得分:45)

Red Gate的SQL Compare产品不仅允许您进行对象级比较,还可以从中生成更改脚本,但它还允许您将数据库对象导出到按对象类型组织的文件夹层次结构中,其中一个[objectname]这些目录中每个对象的.sql创建脚本。对象类型层次结构如下:

\函数
\安全
\安全\角色
\安全\架构
\安全\用户
\存储程序
\表

如果在进行更改后将脚本转储到同一根目录,则可以使用它来更新SVN仓库,并单独保留每个对象的运行历史记录。

答案 2 :(得分:39)

这是围绕发展的“难题”之一。据我所知,没有完美的解决方案。

如果您只需要存储数据库结构而不是数据,则可以将数据库导出为SQL查询。 (在企业管理器中:右键单击数据库 - >生成SQL脚本。我建议在选项选项卡上设置“为每个对象创建一个文件”)然后可以将这些文本文件提交到svn并使用svn的diff和logging功能。

我将这与捆绑脚本捆绑在一起,该脚本需要一些参数并设置数据库。我还添加了一些其他查询,用于输入默认数据,如用户类型和管理员用户。 (如果你想了解更多信息,请发布一些内容,我可以将脚本放在可以访问的地方)

如果您还需要保留所有数据,我建议您备份数据库并使用Redgate(http://www.red-gate.com/)产品进行比较。它们并不便宜,但它们值得每一分钱。

答案 3 :(得分:38)

首先,您必须选择适合您的版本控制系统:

  • 集中版本控制系统 - 用户在处理文件之前/之后签出/签入的标准系统,文件保存在单个中央服务器中

  • 分布式版本控制系统 - 正在克隆存储库的系统,每个克隆实际上是存储库的完整备份,因此如果任何服务器崩溃,则可以使用任何克隆的存储库来还原它 在根据需要选择合适的系统后,您需要设置存储库,这是每个版本控制系统的核心 所有这些都在以下文章中解释:http://solutioncenter.apexsql.com/sql-server-source-control-part-i-understanding-source-control-basics/

设置存储库后,如果中央版本控制系统是工作文件夹,您可以阅读this article。它显示了如何使用以下命令在开发环境中设置源代码控制:

  • 通过MSSCCI提供程序的SQL Server Management Studio,

  • Visual Studio和SQL Server数据工具

  • 第三方工具ApexSQL Source Control

答案 4 :(得分:24)

在Red Gate,我们提供了一个工具SQL Source Control,它使用SQL Compare技术将您的数据库与TFS或SVN存储库相链接。此工具集成到SSMS中,让您可以像平常一样工作,除了它现在允许您提交对象。

对于基于迁移的方法(更适合自动部署),我们提供SQL Change Automation(以前称为ReadyRoll),它创建和管理一组增量脚本作为Visual Studio项目。

在SQL源代码管理中,可以指定静态数据表。它们作为INSERT语句存储在源代码控制中。

如果您正在讨论测试数据,我们建议您使用工具或通过您定义的部署后脚本生成测试数据,或者只是将生产备份还原到开发环境。

答案 5 :(得分:21)

你可能想看看Liquibase(http://www.liquibase.org/)。即使您不使用该工具本身,它也可以很好地处理数据库更改管理或重构的概念。

答案 6 :(得分:18)

为每个推荐RedGate工具的人提供+1,并附加建议和警告。

SqlCompare还有一个体面的文档:例如,您可以编写一个控制台应用程序,它将您的源控制脚本文件夹与签入时的CI集成测试数据库同步,以便当有人检查对架构的更改时他们的脚本文件夹会随着匹配的应用程序代码更改自动部署。这有助于缩小与那些忘记将本地数据库中的更改传播到共享开发数据库的开发人员的差距(我认为大约有一半,我认为:))。

需要注意的是,使用脚本化解决方案或其他方法,RedGate工具非常流畅,很容易忘记抽象背后的SQL现实。如果重命名表中的所有列,则SqlCompare无法将旧列映射到新列,并将删除表中的所有数据。它会产生警告,但我看到有人点击过去。我认为,值得一提的是,到目前为止,您只能自动执行数据库版本控制和升级 - 抽象非常漏洞。

答案 7 :(得分:15)

使用VS 2010,使用数据库项目。

  1. 编写数据库
  2. 更改脚本或直接更改 您的数据库服务器
  3. 使用数据同步>     架构比较
  4. 制作完美的数据库版本控制解决方案,使数据库同步变得轻而易举。

答案 8 :(得分:15)

我们使用DBGhost来管理我们的SQL数据库。然后,您将脚本放在版本控制中构建一个新数据库,它将构建一个新数据库,或者将任何现有数据库升级到版本控制中的模式。这样您就不必担心创建更改脚本(尽管您仍然可以这样做,例如,如果您想更改列的数据类型并需要转换数据)。

答案 9 :(得分:13)

使用更改脚本将数据库脚本保存到版本控制是一种很好的方法,这样您就可以升级任何一个数据库。此外,您可能希望为不同版本保存模式,以便您可以创建完整数据库而无需应用所有更改脚本。处理脚本应该是自动化的,这样您就不必进行手动工作。

我认为为每个开发人员创建一个单独的数据库并且不使用共享数据库很重要。这样,开发人员可以独立于其他开发人员创建测试用例和开发阶段。

自动化工具应该具有处理数据库元数据的方法,它可以告诉哪些数据库处于什么开发状态,哪些表包含版本可控数据等等。

答案 10 :(得分:12)

您还可以查看迁移解决方案。这些允许您使用C#代码指定数据库模式,并使用MSBuild上下滚动数据库版本。

我目前正在使用DbUp,而且效果很好。

答案 11 :(得分:11)

您没有提及有关目标环境或约束的任何细节,因此这可能不完全适用......但如果您正在寻找一种方法来有效跟踪不断发展的数据库架构并且不会对使用Ruby的想法,ActiveRecord的迁移就在你的小巷里。

迁移使用Ruby DSL以编程方式定义数据库转换;每个转换都可以应用或(通常)回滚,允许您在任何给定的时间点跳转到不同版本的数据库模式。定义这些转换的文件可以像任何其他源代码一样检入版本控制。

由于迁移是ActiveRecord的一部分,因此它们通常可用于全栈Rails应用程序;但是,您可以轻松地使用独立于Rails的ActiveRecord。有关在Rails之外使用AR迁移的更详细的处理,请参阅here

答案 12 :(得分:10)

每个数据库都应该受源代码控制。缺少的是一个自动编写所有数据库对象 - 和“配置数据” - 到文件的工具,然后可以将其添加到任何源控制系统。如果您使用的是SQL Server,那么我的解决方案就在这里:http://dbsourcetools.codeplex.com/。玩得开心。 - 内森。

答案 13 :(得分:9)

很简单。

  1. 当基础项目准备好后,您必须创建完整的数据库脚本。此脚本已提交给SVN。这是第一个版本。

  2. 之后,所有开发人员都会创建更改脚本(ALTER ...,新表,sprocs等)。

  3. 当您需要当前版本时,您应该执行所有新的更改脚本。

  4. 当应用程序发布到生产环境时,你会回到1(但那时它将是连续版本)。

  5. Nant将帮助您执行这些更改脚本。 :)

    请记住。当有纪律时,一切都很好。每次提交数据库更改时,代码中的相应函数也会被提交。

答案 14 :(得分:8)

要使转储到源代码控制系统的速度稍微快一点,您可以通过使用sysobjects中的版本信息查看自上次以来哪些对象已更改。

设置:在每个要逐步检查的数据库中创建一个表,以保存上次检查时的版本信息(第一次运行时为空)。如果要重新扫描整个数据结构,请清除此表。

IF ISNULL(OBJECT_ID('last_run_sysversions'), 0) <> 0 DROP TABLE last_run_sysversions
CREATE TABLE last_run_sysversions (
    name varchar(128), 
    id int, base_schema_ver int,
    schema_ver int,
    type char(2)
)

正常运行模式:您可以从此sql获取结果,并为您感兴趣的那些生成sql脚本,并将它们放入您选择的源代码控制中。

IF ISNULL(OBJECT_ID('tempdb.dbo.#tmp'), 0) <> 0 DROP TABLE #tmp
CREATE TABLE #tmp (
    name varchar(128), 
    id int, base_schema_ver int,
    schema_ver int,
    type char(2)
)

SET NOCOUNT ON

-- Insert the values from the end of the last run into #tmp
INSERT #tmp (name, id, base_schema_ver, schema_ver, type) 
SELECT name, id, base_schema_ver, schema_ver, type FROM last_run_sysversions

DELETE last_run_sysversions
INSERT last_run_sysversions (name, id, base_schema_ver, schema_ver, type)
SELECT name, id, base_schema_ver, schema_ver, type FROM sysobjects

-- This next bit lists all differences to scripts.
SET NOCOUNT OFF

--Renamed.
SELECT 'renamed' AS ChangeType, t.name, o.name AS extra_info, 1 AS Priority
FROM sysobjects o INNER JOIN #tmp t ON o.id = t.id
WHERE o.name <> t.name /*COLLATE*/
AND o.type IN ('TR', 'P' ,'U' ,'V')
UNION 

--Changed (using alter)
SELECT 'changed' AS ChangeType, o.name /*COLLATE*/, 
       'altered' AS extra_info, 2 AS Priority
FROM sysobjects o INNER JOIN #tmp t ON o.id = t.id 
WHERE (
   o.base_schema_ver <> t.base_schema_ver
OR o.schema_ver      <> t.schema_ver
)
AND  o.type IN ('TR', 'P' ,'U' ,'V')
AND  o.name NOT IN ( SELECT oi.name 
         FROM sysobjects oi INNER JOIN #tmp ti ON oi.id = ti.id
         WHERE oi.name <> ti.name /*COLLATE*/
         AND oi.type IN ('TR', 'P' ,'U' ,'V')) 
UNION

--Changed (actually dropped and recreated [but not renamed])
SELECT 'changed' AS ChangeType, t.name, 'dropped' AS extra_info, 2 AS Priority
FROM #tmp t
WHERE    t.name IN ( SELECT ti.name /*COLLATE*/ FROM #tmp ti
         WHERE NOT EXISTS (SELECT * FROM sysobjects oi
                           WHERE oi.id = ti.id))
AND  t.name IN ( SELECT oi.name /*COLLATE*/ FROM sysobjects oi
         WHERE NOT EXISTS (SELECT * FROM #tmp ti
                           WHERE oi.id = ti.id)
         AND   oi.type  IN ('TR', 'P' ,'U' ,'V'))
UNION

--Deleted
SELECT 'deleted' AS ChangeType, t.name, '' AS extra_info, 0 AS Priority
FROM #tmp t
WHERE NOT EXISTS (SELECT * FROM sysobjects o
                  WHERE o.id = t.id)
AND t.name NOT IN (  SELECT oi.name /*COLLATE*/ FROM sysobjects oi
         WHERE NOT EXISTS (SELECT * FROM #tmp ti
                           WHERE oi.id = ti.id)
         AND   oi.type  IN ('TR', 'P' ,'U' ,'V'))
UNION

--Added
SELECT 'added' AS ChangeType, o.name /*COLLATE*/, '' AS extra_info, 4 AS Priority
FROM sysobjects o
WHERE NOT EXISTS (SELECT * FROM #tmp t
                  WHERE o.id = t.id)
AND      o.type  IN ('TR', 'P' ,'U' ,'V')
AND  o.name NOT IN ( SELECT ti.name /*COLLATE*/ FROM #tmp ti
         WHERE NOT EXISTS (SELECT * FROM sysobjects oi
                           WHERE oi.id = ti.id))
ORDER BY Priority ASC

注意:如果您在任何数据库中使用非标准排序规则,则需要将/* COLLATE */替换为数据库排序规则。即COLLATE Latin1_General_CI_AI

答案 15 :(得分:8)

因为我们的应用程序必须跨多个RDBMS工作,所以我们使用数据库中立的Torque格式(XML)将我们的模式定义存储在版本控制中。我们还以XML格式对数据库的参考数据进行版本控制,如下所示(其中“Relationship”是参考表之一):

  <Relationship RelationshipID="1" InternalName="Manager"/>
  <Relationship RelationshipID="2" InternalName="Delegate"/>
  etc.

然后,我们使用自行开发的工具生成架构升级和参考数据升级脚本,这些脚本需要从数据库的X版本升级到版本X + 1.

答案 16 :(得分:8)

如果你有一个小型数据库而你想对整个版本进行版本化,那么this batch script可能有所帮助。它将MSSQL数据库MDF文件分离,压缩和检查到Subversion。

如果您主要想要对架构进行版本控制并且只有少量参考数据,则可以使用SubSonic Migrations来处理它。这样做的好处是您可以轻松地向上或向下迁移到任何特定版本。

答案 17 :(得分:7)

我们需要在迁移到x64平台之后对我们的SQL数据库进行版本控制,而我们的旧版本已经破坏了迁移。我们编写了一个C#应用程序,它使用SQLDMO将所有SQL对象映射到一个文件夹:

                Root
                    ServerName
                       DatabaseName
                          Schema Objects
                             Database Triggers*
                                .ddltrigger.sql
                             Functions
                                ..function.sql
                             Security
                                Roles
                                   Application Roles
                                      .approle.sql
                                   Database Roles
                                      .role.sql
                                Schemas*
                                   .schema.sql
                                Users
                                   .user.sql
                             Storage
                                Full Text Catalogs*
                                   .fulltext.sql
                             Stored Procedures
                                ..proc.sql
                             Synonyms*
                                .synonym.sql
                             Tables
                                ..table.sql
                                Constraints
                                   ...chkconst.sql
                                   ...defconst.sql
                                Indexes
                                   ...index.sql
                                Keys
                                   ...fkey.sql
                                   ...pkey.sql
                                   ...ukey.sql
                                Triggers
                                   ...trigger.sql
                             Types
                                User-defined Data Types
                                   ..uddt.sql
                                XML Schema Collections*
                                   ..xmlschema.sql
                             Views
                                ..view.sql
                                Indexes
                                   ...index.sql
                                Triggers
                                   ...trigger.sql

然后,应用程序会将新编写的版本与存储在SVN中的版本进行比较,如果存在差异,则会更新SVN。 我们确定每晚运行一次就足够了,因为我们没有对SQL进行那么多的更改。它允许我们跟踪我们关心的所有对象的更改,并且它允许我们在发生严重问题时重建我们的完整模式。

答案 18 :(得分:7)

我刚才写了这个应用程序http://sqlschemasourcectrl.codeplex.com/,它会根据需要经常扫描你的MSFT SQL数据库,并自动将你的对象(表,视图,过程,函数,sql设置)转储到SVN中。奇迹般有效。我在Unfuddle中使用它(允许我在签到时收到警报)

答案 19 :(得分:7)

我们不存储数据库模式,我们将更改存储到数据库中。我们所做的是存储架构更改,以便为任何版本的数据库构建更改脚本并将其应用于客户的数据库。我编写了一个数据库实用程序应用程序,它与我们的主应用程序一起分发,可以读取该脚本并知道需要应用哪些更新。它还有足够的智能来根据需要刷新视图和存储过程。

答案 20 :(得分:6)

我们刚开始使用Team Foundation Server。如果您的数据库是中等大小,那么visual studio可以与内置的比较,数据比较,数据库重构工具,数据库测试框架甚至数据生成工具进行一些很好的项目集成。

但是,该模型不适合非常大或第三方数据库(加密对象)。所以,我们所做的只是存储我们的自定义对象。 Visual Studio / Team Foundation服务器非常适用于此。

TFS Database chief arch. blog

MS TFS site

答案 21 :(得分:6)

我同意ESV的回答,并且出于某种原因,我在一段时间内开始了一个小项目,以帮助维护一个非常简单的文件中的数据库更新,然后可以维护一个长边的源代码。它允许轻松更新开发人员以及UAT和Production。该工具适用于Sql Server和MySql。

一些项目功能:

  • 允许架构更改
  • 允许值树种群
  • 允许单独的测试数据插入,例如。 UAT
  • 允许回滚选项(非自动化)
  • 维护对SQL Server和Mysql的支持
  • 能够使用一个简单的命令将现有数据库导入版本控制(仅限sql server ...仍在使用mysql)

代码托管在Google代码上。请查看Google代码以获取更多信息

http://code.google.com/p/databaseversioncontrol/

答案 22 :(得分:6)

典型的解决方案是根据需要转储数据库并备份这些文件。

根据您的开发平台,可能有开源插件可用。滚动自己的代码来完成它通常是相当微不足道的。

注意:您可能希望备份数据库转储,而不是将其置于版本控制中。这些文件在版本控制中会变得非常快,并导致整个源代码控制系统变慢(我现在回想起CVS恐怖故事)。

答案 23 :(得分:5)

我也在数据库中使用通过数据库扩展属性系列程序存储的版本。我的应用程序有每个版本步骤的脚本(即从1.1移动到1.2)。部署后,它会查看当前版本,然后逐个运行脚本,直到它到达最后一个应用程序版本。没有脚本具有直接的“最终”版本,即使部署在干净的数据库上,也可以通过一系列升级步骤进行部署。

现在我想补充的是,我两天前在MS校园里看到过有关新的和即将推出的VS DB版本的演示。演讲专注于这个主题,我被吹走了。您一定要查看它,新设施专注于在T-SQL脚本(CREATE)中保持模式定义,运行时增量引擎将部署模式与定义的模式进行比较,并执行增量ALTER和与源代码集成的集成,最多并包括用于自动构建丢弃的MSBUILD持续集成。该drop将包含一个新的文件类型,即.dbschema文件,可以将其带到部署站点,命令行工具可以执行实际的“增量”并运行部署。 我有关于此主题的博客条目以及VSDE下载的链接,您应该查看它们:http://rusanu.com/2009/05/15/version-control-and-your-database/

答案 24 :(得分:5)

前段时间我发现了一个VB bas模块,该模块使用DMO和VSS对象将整个数据库脚本化为VSS。我将其转换为VB脚本并将其发布为here。您可以轻松取出VSS调用并使用DMO生成所有脚本,然后从调用VBScript的同一批处理文件中调用SVN来检查它们吗?

Dave J

答案 25 :(得分:4)

这是一个非常古老的问题,但是现在很多人都试图解决这个问题。他们所要做的就是研究Visual Studio数据库项目。没有这个,任何数据库开发看起来都很虚弱。从代码组织到部署再到版本控制,它简化了一切。

答案 26 :(得分:3)

根据我的经验,解决方案有两个方面:

  1. 您需要处理开发期间由多个开发人员完成的开发数据库更改。

  2. 您需要在客户站点处理数据库升级。

  3. 为了处理#1,你需要一个强大的数据库差异/合并工具。最好的工具应该能够尽可能多地执行自动合并,同时允许您手动解决未处理的冲突。

    完美的工具应该使用3向合并算法来处理合并操作,该算法考虑了相对于BASE数据库在THEIRS数据库和MINE数据库中所做的更改。

    我编写了一个商业工具,为SQLite数据库提供手动合并支持,我目前正在为SQLite添加对3向合并算法的支持。请查看http://www.sqlitecompare.com

    为了处理#2,您需要一个升级框架。

    基本思想是开发一个自动升级框架,该框架知道如何从现有SQL模式升级到较新的SQL模式,并可以为每个现有数据库安装构建升级路径。

    http://www.codeproject.com/KB/database/sqlite_upgrade.aspx查看我关于这个主题的文章,以便大致了解我在说什么。

    祝你好运

    Liron Levi

答案 27 :(得分:3)

查看DBGhost http://www.innovartis.co.uk/。我已经以自动化的方式使用了2年,而且效果很好。它允许我们的数据库构建发生很像Java或C构建发生,除了数据库。你知道我的意思。

答案 28 :(得分:2)

我建议使用比较工具即兴创建数据库的版本控制系统。一个很好的选择是xSQL Schema ComparexSQL Data Compare

现在,如果您的目标是仅在版本控制下使用数据库架构,则只需使用xSQL架构比较生成架构的xSQL快照,并在版本控制中添加这些文件。要恢复或更新到特定版本,只需将当前版本的数据库与目标版本的快照进行比较。

唉,如果你想在版本控制下拥有数据,你可以使用xSQL Data Compare为你的数据库生成更改脚本,并在你的版本控制中添加.sql文件。然后,您可以执行这些脚本以还原/更新到您想要的任何版本。请记住,对于&#39;还原&#39;生成更改脚本所需的功能,这些脚本在执行时将使版本3与版本2相同,并且用于“更新”。功能,您需要生成相反的更改脚本。

最后,通过一些基本的批处理编程技巧,您可以使用命令行版本的xSQL架构比较和xSQL数据比较自动化整个过程

免责声明:我是xSQL的附属公司。