如何部署SQL Server数据库?

曾经有一段时间,使用RDBMS的唯一方法是在使用大容量复制实用程序输出其数据之后,将现有版本脱机,然后从执行的一个脚本中创建新版本以创建数据库。然后,用导出的数据填充数据库,最后使系统恢复在线状态。如何使用单个脚本达到这一点是另一回事。它可能最初是从实体关系图表工具或某些其他设计工具生成的输出。如果有更简单,更可靠的方法,即使是最狂热的数据库设计人员也不会手工剪切表构建脚本。

该ALTER TABLE命令稍后发布到SQL。这为数据库开发人员提供了在保留其数据的同时选择更改现有数据库的机会,尽管只有少数情况下,RDBMS可以在没有补充脚本的情况下做到这一点。如果使用了这种“迁移”脚本,那么会同时更改匹配的构建脚本,以便随后可以从头开始创建“更改的”对象。

如今,开发和部署数据库的方式取决于应用程序和设置的类型。零售银行或政府部门将不会容忍某些“初创”文化的做法。但是,任何组织都普遍认为,必须有可能从源代码构建数据库,该源代码存放在团队可见的存储库中。除此之外,开发团队还应拥有选择最合适的开发和发布系统的自由。

我建议,尽管现有数据库应用程序的发布过程应以测试和使用一个或多个保留现有数据的迁移脚本为主导,但是常规的自动构建是开发数据库最快,最省心的方式,只要记录并解决了每个潜在的数据迁移问题,便可以解决问题。

一个团队如何在没有“敲头”的情况下一起完成一个脚本?

使用单个构建脚本文档,很容易与更新产生冲突,这些更新会干扰其他开发人员的并发工作。解决方案是使用SQLCMD脚本,该脚本以正确的顺序提取所需数量的独立文件。然后,您可以像往常一样使用源代码控制来跟踪每个对象的演变。该-i命令行选项允许你指定的文件列表。SQLCMD在按照指定的顺序执行它们之前检查它们是否全部存在。每个组件文件都可以放在源代码管理中。由于每个文件都可以依次列出:r在文件中使用SQLCMD命令,即使使用最复杂的数据库,也不会被迫拥有大型脚本文件,并且可以保证以指定的正确顺序执行它们。使用迁移脚本,每个发行版都需要自己的脚本,并且只能用于从一个版本迁移到下一个“目标”版本。这在源代码管理中,并且像其他任何文件一样对待。可以轻松地将它们链接在一起,以将目标移动到多个版本级别。

为什么这些单独的脚本文件必须全部按顺序排列?

甚至表也取决于所定义的其他SQL Server组件。例如,当您拥有UDT(用户定义的数据类型)时,需要在表之前放置这些UDT。在还创建它们引用的对象之前,不能创建函数。您需要在创建的表中放置所有约束和引用,因此易于理解设计,这意味着通常需要以正确的依赖关系顺序来构建表。这些仅仅是示例。出于不同的原因,必须按顺序对迁移文件进行排序:如果您需要移动一个现有数据库多个版本步骤。按照惯例,迁移脚本会从一个版本转移到另一个版本。要升级两个版本步骤,请先迁移到下一个版本,然后再迁移到下一个版本。

我不能仅将自己限制在不引起依赖关系的SQL Server对象上吗?UDT和函数毕竟有点深奥。

您将不是第一个尝试这样做的人,但是也许您将是第一个成功的人。无论如何,祝你好运。

如何以正确的顺序获取所有源文件?

如果您继承了混乱,则取决于混乱程度。如果您已经拥有最新的工作数据库,则可以使用SSMS生成一个单文件构建脚本,该脚本将告诉您正确的顺序。如果没有当前的数据库构建,如果将所有文件放在一个目录中,则完全有可能使SQL Compare从混乱(源)生成单个文档构建脚本(目标)。您只需将凌乱的目录与空数据库同步,或/empty2在SQL Compare中使用方便的开关即可。

如果您将源文件夹和目标文件夹都设置为脚本文件夹,则它将源目录中的混乱情况带入目标文件夹中,并且将它们整齐地整理。在使用它时,它甚至可以像您的母亲一样工作,可以通过将每个表和例程的源代码分别整齐地放置在一个目录中(每个类型的数据库对象都有一个子目录,每个数据库对象一个文件)来清理原始混乱。表或其他类型的数据库对象:(同时使源和目标成为源目录)。

无论选择哪种方式获取单个文档构建脚本,都会告诉您构建数据库的正确顺序。然后,您只需要创建一个SQLCMD文件即可,该文件指定了正确的脚本执行顺序,并且有了修改和扩展数据库的基础。像SQL Change Automation这样的工具也可以让您建立脚本的部署顺序,但是您必须更改文件名。无论如何,您都可以直接从该目录进行构建,并且可以插入任何必要的DML脚本。相似文件可以依次管理一组迁移脚本,以将新版本发布到生产环境。

为什么不继续从所有脚本文件生成单文档构建脚本呢?

时间,精力和可重复性。如果需要,熟练的数据库开发团队不会考虑每天几次重建数据库。前几天,我在一小时内建立了一个数据库二十次。这意味着他们可以很快地掉头解决设计错误,从而减少了尝试不同策略或使用导致更多依赖关系的功能时受到的抑制。即使不是很重要,他们也要定期进行操作,以便第一个知道依赖关系变化的人。

当您使用SQL Compare创建单文档脚本时,它不只是执行SQL文件,还会解析这些文件,使用它们构建源数据库的模型,然后将其与目标数据库进行比较。然后,它生成自己的SQL,以使目标与源相同。对于构建而言,这无关紧要,即使任何DML(例如添加扩展属性,插入参考数据或枚举)都将丢失。但是,在创建部署脚本时,狡猾的迁移步骤将不再存在。

迁移脚本方法解决的所有那些问题呢?

数据库构建没有任何此类问题。迁移脚本解决了在保留现有数据的同时更新现有数据库的问题,而不是构建数据库的问题。从头开始建立数据库然后将数据放入其中要比在其中存放数据要容易得多,就像在居民搬进来之前盖房子要容易一样。迁移就像盖一栋房子。房屋扩建,房屋仍被占用;可能性差不多,但这是另一个问题。另外,如果使用ALTER TABLE语句升级数据库,则需要进行额外的工作,以确保更改也反映CREATE在源代码管理的构建脚本中。

那为什么还要担心迁移呢?

迁移对于部署很重要。一旦完成测试,并且团队对于发布候选版本适合发布并因此准备好进行部署管道(测试,UAT,登台等)感到高兴,他们就需要创建并彻底测试迁移脚本。

此迁移脚本仅在将数据库从一个精确版本更改为另一精确版本时有用。当您准备进行发布时,您将专注于执行迁移脚本。SQL Compare可以自动生成一个初次迁移的脚本,但是如果您完成了重命名表或重新设计整个数据模型之类的尴尬事情,那么不可避免的是,您必须手动剪切一些代码以使其包含在内。保留现有数据。这将需要测试,并且其中一些测试将需要在暂存中。

您可以不迁移就释放数据库吗?

曾经有一次只能建立SQL数据库,而不能更改。在那些日子里,我们必须使应用程序脱机,导出数据,然后将数据导入新版本,然后再使其重新联机。如果数据模型已更改,则需要一个特殊的例程来保存数据,以便可以将其导入新的表结构中,或者以导出格式(例如CSV)更改数据。您也可以将数据导入到同一服务器上现有数据库的临时版本中,并根据需要迁移数据,对数据进行切片和切块以适应新模型。在整个应用程序脱机的情况下,您将等待,鼓动手指并尝试忽略电话,而数据仍在滑动,您希望不会出现故障。

因此,既然我们有了一个迁移脚本,该脚本只将精确版本带到下一个版本,那么我们如何应对可能存在的其他版本?

每个候选候选版本都带有一个迁移脚本,该脚本将采用生产数据库或任何存储有数据的数据库,从当时存在的生产版本到候选候选版本。为了脱离其他版本,请依次为每个版本应用迁移脚本。

哇,所以我可以一个接一个地应用每个迁移脚本来从头开始构建数据库!

如果按顺序执行它们并具有完整的设置,它将这样做,但是迁移脚本的重点是保留现有的应用程序数据。当包含第一个版本的现有表中的数据甚至不存在时,您将如何从中获取数据?

不。您要做的就是概括每个失败的设计错误和更正,而您将没有数据。另一个问题是,任何构建脚本都应该成功执行,否则就不会留下任何痕迹。这通常意味着在事务内进行操作,但是即使这样事情也会变得复杂,有时您必须在事务外进行部分操作。在这种情况下,您必须“扑朔迷离”。如果将一系列迁移脚本应用在字符串中,则它们必须整齐地失败,以便它们像启动前一样离开数据库。这不容易。

除非您还将每个更改都保存到对象的CREATE脚本中,否则您将无法从源代码管理中受益,因为他们知道谁做了什么,何时做以及为什么做。您无法从迁移脚本中获得此信息。这是基本的问责制和监督。您如何对表的更改进行审核跟踪?

在开发中使用迁移脚本似乎要简单得多

如果您是单个开发人员,则使用生产数据的副本,那么可以。但是,大多数数据库开发人员都需要通过调整代码来犯错,尝试一下并优化性能。如果每个步骤都是一个迁移文件,那么这些文件将不可避免地堆叠在一起。在一个发行版中包含数百个迁移文件并不鲜见。在某些时候,您必须将它们合并为一个迁移。然后,您在该项目上还有另一个开发人员。您无意中更改了相同的迁移步骤,因为您俩都在处理重要的表或过程集。然后,您必须通过合并两个分支来解决这些冲突。然后,您发现该应用程序具有人员的姓名和地址,也许其他详细信息未加密。

即使您解决了所有这些问题并确定了如何在源代码管理中维护源代码,将迁移脚本与更新后的数据应用于生产服务器时,仍然可能会陷入困境。典型的例子是Null或O’Brien家族的成员同时注册使用您的系统。

您如何处理表结构中的更改,这些更改将导致数据不再导入?

当您对一个或一组表进行“重大更改”时,您将准备,测试并执行准备数据的迁移代码。这可能是数据存储位置的更改,但很可能是处理CHECK约束的更改,列可为性(NULL to NOT NULL)的更改或额外的唯一约束或外键。您执行代码来修复数据,并确保将其放置在新构建的正确位置和格式中。然后,将代码添加到文件中,该文件将成为下一个版本的迁移脚本。

然后,您将数据另存为下一个构建的新构建数据。下次常规构建可能会出错,但是没有人受伤。在准备迁移脚本时,这些错误都是有价值的见解。

为什么要在开发中反复构建数据库呢?

即使只处理一个版本或数据库变体,也可能至少有两个数据库副本在开发中。您将拥有一份副本,可以在无法打扰他人,拆除,重建和试验的情况下犯下难以言喻的罪行。您将拥有另一个共享的资源,可用于对已签入的更改进行回归测试。您可能还有其他具有不同数据集或变体的对象。一切都必须与签入的源代码保持最新。您将拥有不同的标准数据集,因为毕竟,测试端到端流程的最快方法是从一组定义的数据开始,然后查看是否得出正确的结果。

您还必须与应用程序开发保持同步。通常,数据库只是应用程序的一小部分。如果整个应用程序的开发人员都在进行或测试重大更改,则需要提供至少一个数据库副本以与进度保持同步,尤其是在应用程序与数据库紧密耦合的情况下,尤其如此。直接访问表。他们将要测试他们的代码,以使其支持并正在构建的数据库逐步升级。它可能与您正在尝试的步骤版本不同。

我的数据库是如此庞大,以至于我无法从头开始构建。我必须迁移它

构建过程必须完全自动化和优化,因为它过程缓慢且乏味。此外,正如我的数字朋友不断提醒我的那样,人类在疲倦时容易出错。插入数据可能是一个缓慢的过程,但是如果您在禁用约束的情况下使用本机BCP,则数据库的大小必须相当合理才能超过过夜的构建。您很快会发现,开发周期自然属于使用夜间构建的情况。如果您的开发团队处于截然不同的时区,这可能很尴尬,但是我发现总是有一个“死角”可以安排常规构建。

即使开发数据库太大而无法进行一整夜的构建,也不必担心。这不是一个新问题,并且有解决方案。大多数数据库保存的数据对于数据库的运行是完全不必要的。我从来没有找到一个数据库,其中没有大量的无用和未引用的信息,甚至是图像数据,都在其中挥霍。我们称其为“卧室碗橱综合征”。答案是先加载基本信息。然后,您可以使数据库可用。然后,按其有用性将其余部分作为后台进程加载。没有人会注意到。人类通常仅出于舒适性价值而保留数据。

构建脚本和迁移脚本之间到底有什么区别?

构建脚本和迁移脚本都将数据库从一个版本移植到另一个版本。唯一的区别是,构建脚本将其从基岩迁移到所需版本,同时忽略任何现有数据,因为在此阶段没有任何数据,而迁移脚本保留了现有数据并在两个版本之间对数据进行了必要的更改。通常,将构建脚本包装在事务中仍然是一种好习惯,但通常不是这样,因为在发生错误后很容易将其删除。迁移脚本需要回滚和幂等(即,无意中再次运行它不会造成损害)

我正在努力找出同步脚本和迁移脚本之间的区别?

术语“同步”具有误导性。数据同步通常意味着将所有同步节点上的数据操作传递到其他节点。如果您在移动设备上放了新的MP3,它会出现在笔记本电脑上,反之亦然。如果您在笔记本电脑上删除该Rick Astley单曲,它将在移动设备上被删除。数据库同步脚本使目标数据库与源数据库相同,同时保留其现有数据,反之亦然。迁移脚本从一个版本到下一个版本增量获取数据库及其数据。没有太大的区别。传统上,迁移脚本倾向于“手工切割”,而同步脚本倾向于由第三方工具生成。它们对错误回滚具有相同的要求。

那么,迁移脚本是件好事吗?

好?如果要升级现有的实时系统,则它们在部署管道中始终是必不可少的。您使用它们的次数越多,您生产的无故障版本就越有可能。但是,在选择候选版本之前,数据库开发本身通常要好得多,并且构建起来会更加灵活。

总结

数据库开发人员的任务是使他人的生活尽可能轻松。这意味着要尽早考虑部署,安全,维护,培训,监督和合规性问题。为此,数据库必须处于对象级别的源代码控制中,以便更广泛的团队可以及早检查潜在问题,并可以跟踪更改。每次计划要发布到生产数据库系统的发行版时,都必须在源代码控制中附带一个迁移脚本,该脚本将安全地将生产版本升级到新发行版。因此,必须为数据库标记正确的版本号,以防止发生意外。

我建议定期建立数据库,通常是在一夜之间建立,但如有必要,可以更定期地建立数据库。我建议在开发中使用干净的例行构建,而不是为此例行构建创建并应用新的迁移脚本,这既是因为它省去了不必要的工作,又因为它鼓励使用标准数据集进行例行回归测试。但是,开发人员需要在发布之前仔细标记潜在的数据迁移问题,因此在需要脚本之前就先进行迁移脚本的工作。无论何时签入“重大更改”,他们都会使用许多常规例程所需的例程来准备数据。


修改原文相关链接,尊重他人劳动成果