【问题标题】:How to properly manage database deployment with SSDT and Visual Studio 2012 Database Projects?如何使用 SSDT 和 Visual Studio 2012 数据库项目正确管理数据库部署?
【发布时间】:2013-03-01 14:24:29
【问题描述】:

我正处于研究阶段,试图在现有的小型项目中采用 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 的经历并没有让我对这种策略存在任何希望,但我很想找出不同的答案。

【问题讨论】:

  • 您可能会发现模式比较功能对于保持模式同步很有用。 Link 1 和链接 2 msdn.microsoft.com/en-us/library/aa833202(v=vs.80).aspx
  • 模式比较工具很棒,但它对数据没有任何帮助。某些架构更改需要自定义工作来保存和迁移数据,而架构比较工具不支持这一点。我认为这就是存在部署前和部署后脚本的原因,以帮助处理这种性质的事情。
  • 您可能需要考虑项目的快照,以便您可以按特定顺序发布它们。快照 v1、v2、v3 等。按顺序应用每个,这样当您拥有发布包时就不会丢失任何东西。您可以查询数据库中的表以找出“当前”版本,并通过批处理或 powershell 脚本从 v+1 开始。部署后脚本可以处理在您的表中设置该版本。
  • 希望我早点发现这个问题!据我所知,数据是 SSDT 被遗忘的故事,这很奇怪,因为这就是数据库的全部意义所在。有时感觉他们喜欢在演示中看起来很华丽的东西:(

标签: sql visual-studio-2012 sqlcmd database-project sql-server-data-tools


【解决方案1】:

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

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

所以回答我的场景:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    希望对您有所帮助。

    JT

    【讨论】:

    • 应用程序代码是版本化的,它需要一个特定的数据库模式。因此,模式本质上是版本化的。正如您所描述的,可以使用 SSDT 将架构直接迁移到任何形式并删除应用程序二进制文件以进行匹配,但是在这种情况下如何迁移数据?没有人知道如何自动迁移数据,所以你必须告诉它如何。因此,必须手动编写部署前/部署后脚本。我发现的唯一可管理的策略正如我在回答中所描述的那样,但它完全阻止了跳过中间版本的直接升级。除非我错过了什么……
    • 嗨@darkmyst,我总是编写部署前/部署后脚本,以便它们以与声明的模式相同的幂等方式工作。现在,诚然,这不是一件容易的事,但我(还)没有遇到需要部署临时版本的场景。是的,脚本需要了解这些临时版本中的所有架构更改,这就是它们难以编写的原因 - 但是我确实认为需要部署临时版本否定了 SSDT 的声明性范式,在我看来是使用它的全部意义。只是我的两分钱。
    • 似乎您拥有的版本越多,需要考虑临时版本更改的负担就越大。跟踪所有这些临时更改并测试每个版本的升级路径似乎成倍地乏味和冒险。以自动化方式执行一系列不同的、经过良好测试的升级脚本似乎是避免这种风险的值得权衡的选择。不过,我正在研究声明式数据库开发,并希望看到一个如何开发像您这样的部署脚本的示例。感谢您的回答!
    • 我当然同意测试您的升级是一项值得的努力,并且不会因为您碰巧使用声明式范式而消失 - 这是我向与我合作的团队宣扬的东西。事实上,我认为测试升级很重要,因为您依靠工具来完成人类的工作。不想吹我自己的小号太多,但我在这里写了一篇文章:devproconnections.com/article/sql-server-2012/… 这是试图解释很多这样的东西。
    • @jamiet - 添加到您的建议中,我发现通过自动构建/部署到数据库(或多个数据库)的持续集成可以大大有助于发现部署错误(在构建特定的部署后,未编译的脚本)。此外,在修改对象时,开发人员可以右键单击,找到所有引用以查看任何可能受到影响的部署后脚本。
    【解决方案3】:

    我自己一直在努力,我可以告诉你这并不容易。

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

    遗憾的是,我在 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内置了数据比较工具,还提供了可扩展点 - 也就是说,您现在可以为项目包含构建贡献者和部署计划修改器。

    【讨论】:

    • 您能解释一下如何使用新功能 Deployment Plan Modifiers 吗?
    • 项目已经发展,您可以通过实现 DeploymentContributors 来扩展部署(请参阅 the.agilesql.club/Blogs/Ed-Elliott/…
    【解决方案4】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-04
      相关资源
      最近更新 更多