【发布时间】:2017-10-28 05:26:12
【问题描述】:
我正在开发一个包含许多表、视图和存储过程的软件。目前,为了方便开发人员在其本地数据库上运行所有最新更新并简化软件部署,我们提供了一个大型 Update.sql 文件。这会创建不存在的表和存储过程,并添加/更新/删除需要更改的数据。它旨在一遍又一遍地运行,而不会弄乱某人的数据库,并且只应用所需的更改。这对于开发人员和部署来说非常方便。
但是,我真的很希望能够在源代码控制中将所有数据库对象(表、函数、存储过程、回填/数据更新)拆分为单独的脚本。这将允许我们跟踪对单个数据库对象的更改,而不仅仅是一个大型 SQL 文件。
有没有两全其美的好方法?也许是一个可以运行文件夹及其所有子文件夹中所有 SQL 文件的免费工具?还是某个批处理脚本可以在每次签入后将所有单个文件合并到一个文件中?
编辑 2017 年 10 月 27 日:在查看了答案共享的一些链接之后,我认为这个问题归结为找到一种方法来利用基于状态的 VS 迁移的数据库更新管理的最佳部分。 Here is an article 我认为很好地分解了差异和优缺点,但我将在下面总结我关注的部分
基于状态:这是 Visual Studio SQL Server 项目使用的。它是数据库在当前版本中应该是什么样子的快照。通过将数据库与此快照进行比较并自动生成将更改表/视图/SP/等的脚本来创建对服务器的更新。成为他们需要的样子。
优点:
- 版本控制:每个数据库对象(表、存储过程等)都是一个单独的脚本文件。这使得随着时间的推移跟踪对这些对象所做的更改非常易于管理,因为您只需查看源代码控制历史记录。
- 编译:如果您使用的是 Visual Studio SQL Server 项目,您可以实际编译它们,它们会告诉您您的参考资料是否都很好。例如,如果您在表中删除了一个列,并且有一个存储过程引用了该列,这将告诉您 SP 引用了一个不再存在的列,因此您可以修复它。
- 简单部署:您可以使用这些具有数百个单独数据库对象脚本的项目,并让它在 Visual Studio 中使用 Publish 更新数据库,或者通过编译数据库并将其生成的 DacPac 转换为 SQL 并以这种方式更新数据库。因此,即使有一堆单独的文件,编译后它也只会归结为一个您最终使用的文件。
缺点:
- 更新数据:在现实世界中,基于状态的更新通常是不可行的。例如,假设您的联系人表曾经有一个全名列。在版本 2 中,您决定将其拆分为 First Name 和 Last Name 并删除 Full Name 列。通常,您会编写脚本来添加新列、转换数据,然后删除旧列。但是,基于状态的方法不是这样工作的,它只会删除列并添加新列,而不做任何转换数据的操作。
基于迁移:这几乎是我们目前正在做的事情,除了在一个非常大的文件而不是几个小文件中。您从一个基线(可能是一个空数据库)开始,然后编写一个或多个文件,然后更改该基线以使其成为当前版本。例如,Version1.sql 可能会创建包含 Full Name 列的 Contacts 表,然后 Version2.sql 可能会创建 First Name/Last Name 列,移动数据,然后删除旧列。您可以使用仅按正确顺序运行每个脚本一次的工具,或者您可以执行我们一直在做的事情,并拥有一个包含逻辑的大脚本,以了解哪些事情已经运行,哪些事情没有运行并且只运行需要做什么。
优点和缺点:这基本上与基于状态的相反。它在如何创建脚本方面为您提供了很大的灵活性,以及使用真实逻辑以所需方式更新数据库的能力,而不是让它自动创建 drop/alter/insert/etc。脚本本身。很像基于状态的,只要你有合适的工具,就很容易部署。但是,跟踪对数据库对象所做的更改通常不是很容易。如果我想查看对特定表的更改的完整历史记录、谁以及何时进行的更改,那么实际上并没有一种简单的方法可以做到这一点,因为没有一个文件表示具有源代码控制历史记录的该数据库对象。此外,我还没有看到任何工具可以采用基于迁移的策略并对其进行编译以向您显示所做的更改是否有任何参考问题。
所以,我的问题是:我如何才能保持我们当前使用的基于迁移的功能、灵活性和易用性,同时又获得基于状态的最佳部分(版本控制和编译以检查依赖关系)?只要这并不意味着我的开发人员必须管理两件事(比如编写迁移脚本,但也不要忘记更新 SQL 项目,以便我们可以跟踪历史),我就可以使用一些混合解决方案。如果我可以自动化一个 SQL 项目来根据迁移更新数据库对象脚本,那会很酷,但它需要知道是谁进行了导致更新的更改,并且最好知道它发生在哪个更改集中。
想法?
【问题讨论】:
标签: sql-server deployment version-control