62

我正处于研究阶段,试图在现有的小型项目中采用 2012 年数据库项目。我是 C# 开发人员,而不是 DBA,所以我对最佳实践不是特别精通。我已经搜索 google 和 stackoverflow 几个小时了,但我仍然不知道如何正确处理一些关键部署场景。

1) 在几个开发周期的过程中,我如何管理我的数据库的多个版本?如果我的数据库 v3 上有一个客户端,并且我想将它们升级到 v8,我该如何管理?我们目前为我们产品的每个版本管理手工制作的架构和数据迁移脚本。我们是否仍需要单独执行此操作,或者新范式中是否有某些东西支持或替代它?

2)如果模式以需要移动数据的方式发生变化,处理这个问题的最佳方法是什么?我假设在 Pre-Deployment 脚本中进行了一些工作以保留数据,然后 Post-Deploy 脚本将其放回正确的位置。是这样还是有更好的方法?

3) 任何其他关于如何最好地使用这些新技术的建议或指导也非常感谢!

更新:自从我最初提出这个问题以来,我对这个问题的理解有所增加,虽然我想出了一个可行的解决方案,但这并不是我所希望的解决方案。这是我的问题的改写:

我遇到的问题纯粹是与数据相关的。如果我的应用程序版本 1 上有一个客户端,并且我想将它们升级到我的应用程序版本 5,那么如果他们的数据库没有数据,我这样做不会有任何问题。我只是让 SSDT 智能地比较模式并一次性迁移数据库。不幸的是,客户有数据,所以事情没那么简单。从我的应用程序的版本 1 到版本 2 到版本 3(等等)的架构更改都会影响数据。我目前管理数据的策略要求我为每个版本升级(1 到 2、2 到 3 等)维护一个脚本。这使我无法从应用程序的版本 1 直接转到版本 5,因为我没有数据迁移脚本可以直接转到那里。为每个客户端创建自定义升级脚本或管理升级脚本以从每个版本到每个更高版本的前景呈指数级难以管理。我所希望的是,SSDT 启用了某种策略,使管理事物的数据方面变得更容易,甚至可能与事物的模式方面一样容易。我最近在 SSDT 的经历并没有让我对这种策略存在任何希望,但我很想找出不同的答案。

4

4 回答 4

60

我自己一直在做这件事,我可以告诉你这并不容易。

首先,要解决 JT 的回复 - 即使 SSDT 具有声明性更新机制,您也不能忽略“版本”。SSDT 在将任何源模式移动到任何目标模式方面做了一项“相当不错”的工作(前提是你知道所有的开关和陷阱),这确实不需要验证本身,但它不知道如何管理“数据运动”(至少我看不到!)。因此,就像 DBProj 一样,您可以在 Pre/Post 脚本中使用自己的设备。由于数据移动脚本依赖于已知的开始和结束模式状态,因此您无法避免对数据库进行版本控制。因此,“数据移动”脚本必须应用于模式的版本化快照,这意味着您不能随意将数据库从 v1 更新到 v8 并期望数据移动脚本 v2 到 v8 能够工作(大概,您不会

遗憾的是,我在 SSDT 发布中看不到任何允许我以集成方式处理这种情况的机制。这意味着您必须添加自己的脚手架。

第一个技巧是跟踪数据库(和 SSDT 项目)中的版本。我开始在 DBProj 中使用一个技巧,并将其带到 SSDT,经过一些研究,结果发现其他人也在使用它。您可以将数据库扩展属性应用于数据库本身(称其为“BuildVersion”或“AppVersion”或类似名称),并将版本值应用于它。然后,您可以在 SSDT 项目本身中捕获此扩展属性,SSDT 会将其添加为脚本(然后您可以检查包含扩展属性的发布选项)。然后,我使用 SQLCMD 变量来识别当前传递中应用的源版本和目标版本。一旦确定了源(项目快照)和目标(即将更新的目标数据库)之间的版本增量,您就可以找到所有需要应用的快照。SSDT 部署中,您可能必须将其移动到构建或部署管道(我们使用 TFS 自动部署并有自定义操作来执行此操作)。

下一个障碍是保留模式的快照及其相关的数据移动脚本。在这种情况下,它有助于使脚本尽可能具有幂等性(这意味着,您可以重新运行脚本而不会产生任何不良副作用)。它有助于将可以安全地重新运行的脚本与必须只执行一次的脚本分开。我们对静态参考数据(字典或查找表)做同样的事情 - 换句话说,我们有一个 MERGE 脚本库(每个表一个),它使参考数据保持同步,这些脚本包含在帖子中-部署脚本(通过 SQLCMD :r 命令)。这里要注意的重要一点是,您必须以正确的顺序执行它们,以防这些引用表中的任何一个具有彼此的 FK 引用。我们按顺序将它们包含在主要的部署后脚本中,这有助于我们创建一个为我们生成这些脚本的工具——它还解决了依赖顺序。我们在“版本”结束时运行此生成工具,以捕获静态参考数据的当前状态。您的所有其他数据移动脚本基本上都是特殊情况,并且很可能只是一次性使用。在这种情况下,您可以做以下两件事之一:您可以针对 db build/app 版本使用 IF 语句,或者您可以在创建每个快照包后清除 1 次脚本。

它有助于记住 SSDT 将禁用 FK 检查约束,并且仅在部署后脚本运行后重新启用它们。例如,这使您有机会填充新的非空字段(顺便说一句,您必须启用为非空列生成临时“智能”默认值的选项才能使其工作)。但是,仅对 SSDT 由于架构更改而重新创建的表禁用 FK 检查约束。对于其他情况,您有责任确保数据移动脚本以正确的顺序运行以避免检查约束投诉(或者您在脚本中手动禁用/重新启用它们)。

DACPAC 可以帮助您,因为 DACPAC 本质上是一个快照。它将包含几个描述架构的 XML 文件(类似于项目的构建输出),但在您创建它时会及时冻结。然后,您可以使用 SQLPACKAGE.EXE 或部署提供程序发布该包快照。我还没有完全弄清楚如何使用 DACPAC 版本控制,因为它更依赖于“注册”数据应用程序,所以我们坚持使用自己的版本控制方案,但我们确实将自己的版本信息放入 DACPAC 文件名。

我希望我能提供一个更有说服力和详尽的例子,但我们仍在解决这里的问题。

SSDT 真正糟糕的一件事是,与 DBProj 不同,它目前不可扩展。尽管它在很多不同的事情上都比 DBProj 做得更好,但你不能覆盖它的默认行为,除非你能在前/后脚本中找到解决问题的方法。我们现在试图解决的问题之一是,当您拥有数千万条记录时,重新创建更新表 (CCDR) 的默认方法确实很糟糕。

-更新:我已经有一段时间没有看到这个帖子了,但显然它最近很活跃,所以我想我会添加一些重要的注意事项:如果你使用的是 VS2012,2013 年 6 月发布的 SSDT 现在有一个数据内置比较工具,还提供扩展点——也就是说,您现在可以为项目包含 Build Contributors 和 Deployment Plan Modifiers。

于 2013-04-30T23:37:44.387 回答
9

我还没有真正找到关于这个主题的更多有用信息,但我花了一些时间来了解这些工具、修补和玩耍,我想我已经为我的问题找到了一些可以接受的答案。这些不一定是最好的答案。我仍然不知道是否有其他机制或最佳实践来更好地支持这些场景,但这是我想出的:

给定数据库版本的部署前和部署后脚本仅用于从先前版本迁移数据。在每个开发周期开始时,脚本都会被清理掉,随着开发的进行,它们会被充实为安全地将数据从先前版本迁移到新版本所需的任何 sql。这里的一个例外是数据库中的静态数据。此数据在设计时是已知的,并以 T-SQL MERGE 语句的形式永久存在于部署后脚本中。这有助于使用最新的发布脚本将任何版本的数据库部署到新环境。在每个开发周期结束时,都会生成一个从先前版本到新版本的发布脚本。该脚本将包括生成的用于迁移架构的 sql 和手工制作的部署脚本。是的,我知道发布工具可以直接用于数据库,但这对我们的客户来说不是一个好的选择。我也知道 dacpac 文件,但我不确定如何使用它们。生成的发布脚本似乎是我所知道的生产升级的最佳选择。

所以回答我的场景:

1) 要将数据库从 v3 升级到 v8,我必须为 v4、v5、v6 等执行生成的发布脚本。这与我们现在的操作非常相似。众所周知,数据库项目似乎使创建/维护这些脚本变得更加容易。

2) 当架构从底层数据发生变化时,部署前和部署后脚本用于将数据迁移到新版本所需的位置。受影响的数据基本上在 Pre-Deploy 脚本中备份,并在 Post-Deploy 脚本中放回原处。

3)我仍在寻找有关如何在这些场景和其他场景中最好地使用这些工具的建议。如果我在这里有任何问题,或者我应该注意其他任何问题,请告诉我!谢谢!

于 2013-03-14T19:28:31.397 回答
4

根据我使用 SSDT 的经验,数据库版本号(即 v1、v2...vX 等)的概念有点消失了。这是因为 SSDT 提供了一种称为声明式数据库开发的开发范式,这大致意味着您告诉 SSDT 您希望您的模式处于什么状态,然后让 SSDT 通过与您已有的进行比较来负责使其进入该状态。在这个范例中,部署 v4 然后 v5 等的概念消失了。

正如您正确陈述的那样,您的部署前和部署后脚本是为了管理数据而存在的。

希望有帮助。

捷通

于 2013-04-03T08:23:43.690 回答
3

我只想说,到目前为止,这个线程非常出色。

我一直在努力解决完全相同的问题,并试图在我们的组织中解决这个问题,在一个相当大的遗留应用程序上。我们已经开始向 SSDT 迁移(在 TFS 分支上),但我们确实需要了解部署过程,并在此过程中管理自定义迁移和参考/查找数据。

更复杂的是,我们的应用程序是一个代码库,但可以为每个“客户”定制,所以我们有大约 190 个数据库我们正在处理,对于这个项目,不仅仅是 3 个左右,这可能是正常的。我们一直在进行部署,甚至经常设置新客户。我们现在严重依赖 PowerShell 以及老式的增量发布脚本(以及在该版本中创建新客户的相关脚本)。一旦我们弄清楚这一切,我计划做出贡献,但请分享您学到的任何其他内容。我相信我们最终会维护每个版本的自定义发布脚本,但我们会看到的。在项目中维护每个脚本并包含 From 和 To SqlCmd 变量的想法非常有趣。如果我们这样做,我们可能会一路修剪,

顺便说一句 - 旁注 - 关于最小化浪费的话题,我们还花了很多时间来弄清楚如何自动执行列的正确命名/数据类型约定,以及自动生成所有主键和外键,基于关于命名约定,以及索引和检查约束等。最困难的部分是处理不遵守规则的“偏差”。如果有人感兴趣,也许有一天我也会分享,但现在,我需要大力推进这个部署、迁移和参考数据的故事。再次感谢。就好像你们今天早上在说我脑子里想的东西。

于 2013-05-17T12:53:52.057 回答