如何对SQL Server数据库进行版本控制?

我想让我的数据库处于版本控制之下。

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

如何对数据库应用版本控制?

112352 次浏览

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

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

我将此与一个Batch脚本绑定在一起,该脚本采用一对参数并设置数据库。我还添加了一些额外的查询,输入默认数据,如用户类型和管理用户。(如果你想要更多关于这方面的信息,张贴一些东西,我可以把脚本放在可以访问的地方)

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

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. 备份、清理和收缩生产数据库的脚本。在每次升级到生产DB后运行此命令。
  2. 在开发人员的工作站上恢复(并在必要时调整)备份的脚本。每个开发人员在每次升级到生产DB后都会运行此脚本。

警告:我的自动化测试运行在模式正确但空的数据库上,因此这个建议不能完全满足您的需求。

你没有提到任何关于目标环境或约束的细节,所以这可能并不完全适用……但如果您正在寻找一种有效跟踪不断变化的DB模式的方法,并且不反对使用Ruby, ActiveRecord的迁移正适合您。

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

因为迁移是ActiveRecord的一部分,它们通常在全栈Rails应用程序中使用;然而,你可以用最少的努力独立于Rails使用ActiveRecord。有关在Rails之外使用AR迁移的更详细处理,请参阅在这里

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

根据您的开发平台,可能会有可用的开源插件。编写自己的代码来完成这个任务通常是相当简单的。

注意:您可能希望备份数据库转储,而不是将其放入版本控制中。在版本控制中,文件可能会迅速变大,并导致整个源代码控制系统变慢(我正在回忆CVS的恐怖故事)。

您还可以考虑迁移解决方案。它们允许您在c#代码中指定数据库模式,并使用MSBuild上下滚动数据库版本。

我目前正在使用DbUp,它一直工作得很好。

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

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

如果你有一个小的数据库,你想要版本化整个数据库,这个批处理脚本可能会有帮助。它将MSSQL数据库MDF文件分离、压缩并检入Subversion。

如果你主要想要版本化你的模式,并且只有少量的引用数据,你可以使用亚音速迁移来处理它。这样做的好处是您可以轻松地向上或向下迁移到任何特定的版本。

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

但是,该模型并不适合非常大的或第三方数据库(加密对象)。我们所做的就是只存储我们定制的对象。Visual Studio / Team基础服务器在这方面工作得很好。

TFS数据库主arch。博客< / >

MS TFS site

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

< br > < p > \功能 \安全< br > < br > \安全\角色 < br > \安全\模式 用户\安全\ < br > < br > \存储过程 < / p > \表

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

不久前,我发现了一个VB bas模块,它使用DMO和VSS对象将整个db脚本删除并转换为VSS。我把它变成了一个VB脚本,并发布了在这里。您可以很容易地取出VSS调用并使用DMO东西来生成所有脚本,然后从调用VBScript的同一个批处理文件调用SVN来检入它们。

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

因为我们的应用程序必须跨多个rdbms工作,所以我们使用数据库中立的转矩格式(XML)将模式定义存储在版本控制中。我们还以以下XML格式对数据库的引用数据进行版本控制(其中“关系”是其中一个引用表):

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

然后,我们使用自己开发的工具来生成从数据库版本X到版本X + 1所需的模式升级和引用数据升级脚本。

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

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

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

为了更快地将数据转储到源代码控制系统,您可以使用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脚本生成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

在迁移到x64平台后,我们需要对SQL数据库进行版本调整,而旧版本在迁移过程中出现了问题。我们写了一个c#应用程序,使用sqlmo将所有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做那么多更改。它允许我们跟踪所有我们关心的对象的变化,并且允许我们在发生严重问题时重新构建完整的模式

每个推荐RedGate工具的人都要加1分,还有额外的建议和警告。

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

需要注意的是,使用脚本解决方案或其他方式,RedGate工具足够流畅,以至于很容易忘记抽象背后的SQL现实。如果您重命名表中的所有列,SqlCompare无法将旧列映射到新列,并将删除表中的所有数据。它会产生警告,但我见过有人点击忽略它。这里有一个值得注意的要点,我认为,到目前为止,您只能自动进行DB版本控制和升级——抽象非常容易泄露。

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

现在我想补充的是,我两天前在微软校园看到了一个关于新的和即将到来的VS DB版本的演示。演讲是专门针对这个主题的,我完全被震撼到了。你一定要去看看,新的功能集中在保持模式定义在T-SQL脚本(create),运行时增量引擎来比较部署模式和已定义模式,并进行增量alter和与源代码集成的集成,包括用于自动构建的MSBUILD持续集成。该拖放文件将包含一个新的文件类型,即.dbschema文件,可以将其带到部署站点,命令行工具可以执行实际的“增量”并运行部署。 我有一篇关于这个主题的博客文章,其中有VSDE下载的链接,你应该去看看:http://rusanu.com/2009/05/15/version-control-and-your-database/

这很简单。

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

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

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

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

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

记住。只要有纪律,一切都能顺利进行。每次提交数据库更改时,代码中相应的函数也会被提交。

每个数据库都应该在源代码控制下。目前缺少的是一种工具,可以自动将所有数据库对象(以及“配置数据”)脚本化为文件,然后将其添加到任何源代码控制系统。如果你使用SQL Server,那么我的解决方案是在这里:http://dbsourcetools.codeplex.com/。玩得开心。 -内森。< / p >

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

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

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

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

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

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

为了处理第2点,你需要一个升级框架。

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

请查看我在http://www.codeproject.com/KB/database/sqlite_upgrade.aspx中关于这个主题的文章,以获得我所谈论的内容的大致概念。

祝你好运

Liron利

检查DBGhost http://www.innovartis.co.uk/。我已经在一个自动化的方式使用了2年,它工作得很好。它允许我们的DB构建非常像Java或C构建,除了数据库。你们能明白我的心情

在Red Gate,我们提供了一个工具SQL源代码控制,它使用SQL比较技术将数据库与TFS或SVN存储库链接起来。该工具集成到SSMS中,让您像往常一样工作,只是现在允许提交对象。

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

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

如果您正在讨论测试数据,我们建议您要么使用工具生成测试数据,要么通过您定义的部署后脚本生成测试数据,要么简单地将生产备份恢复到开发环境。

我写了这个应用程序一段时间前,http://sqlschemasourcectrl.codeplex.com/,它会扫描你的MSFT SQL db的经常你想,并自动转储你的对象(表,视图,procs,函数,SQL设置)到SVN。效果非常好。我把它和unduddle一起使用(它可以让我在签到时收到提醒)

我同意ESV的答案,正是出于这个原因,我开始了一个小项目,以帮助维护一个非常简单的文件中的数据库更新,然后可以在一个很长的源代码之外进行维护。它允许对开发人员以及UAT和生产进行轻松的更新。该工具适用于SQL Server和MySQL。

项目的一些特点:

  • 允许模式更改
  • 允许值树填充
  • 允许单独的测试数据插入,例如。UAT
  • 允许回滚选项(不是自动的)
  • 维护对SQL server和MySQL的支持
  • 有能力导入现有的数据库到版本控制与一个简单的命令(SQL server仅…仍在开发MySQL)

请查看代码以获得更多信息。

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

  1. 脚本化数据库
  2. 修改脚本或直接在 您的db服务器
  3. 使用数据>进行同步 李模式比较< / >

使一个完美的DB版本解决方案,并使同步DB的微风。

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

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

  • 集中式版本控制系统——一个标准系统,用户在对文件进行操作之前/之后签出/签入,文件保存在单个中央服务器中

  • 分布式版本控制系统—存储库被克隆的系统,每个克隆实际上都是存储库的完全备份,因此如果任何服务器崩溃,那么任何克隆的存储库都可以用来恢复它 在为您的需求选择了正确的系统之后,您将需要设置存储库,它是每个版本控制系统的核心 所有这些都在下面的文章中解释:http://solutioncenter.apexsql.com/sql-server-source-control-part-i-understanding-source-control-basics/

在建立了存储库之后,如果是中央版本控制系统,则可以读取这篇文章。它展示了如何在开发环境中使用以下命令来设置源代码控制:

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

  • Visual Studio和SQL Server数据工具

  • 一个第三方工具ApexSQL源代码控制

我建议使用比较工具为您的数据库临时设计一个版本控制系统。两个好的替代方法是xSQL模式比较xSQL数据比较

现在,如果您的目标是只对数据库的模式进行版本控制,那么您可以简单地使用xSQL schema Compare来生成模式的xSQL快照,并在版本控制中添加这些文件。然后,要恢复或更新到特定版本,只需将数据库的当前版本与目标版本的快照进行比较。

此外,如果希望数据也处于版本控制之下,可以使用xSQL data Compare为数据库生成更改脚本,并在版本控制中添加.sql文件。然后,您可以执行这些脚本以恢复/更新到您想要的任何版本。请记住,对于“恢复”功能,您需要生成更改脚本,当执行时,将使版本3与版本2相同,对于“更新”功能,您需要生成与之相反的更改脚本。

最后,通过一些基本的批处理编程技能,您可以使用命令行版本的xSQL Schema Compare和xSQL Data Compare来自动化整个过程

免责声明:我隶属于xSQL。

版本控制数据库的另一种选择是使用版本控制数据库,现在有几个这样的数据库。

https://www.dolthub.com/blog/2021-09-17-database-version-control/

这些产品没有在其他类型的数据库上应用版本控制——它们是自己的数据库引擎,支持版本控制操作。因此,您需要迁移到它们,或者在它们的基础上开始构建。

我编写了其中一个,DoltDB,它结合了MySQL和Git的接口。看看这里:

https://github.com/dolthub/dolt