数据库脚本在代码控制下的最佳实践是什么?

24

我们目前正在审查如何在subversion中存储数据库脚本(表、存储过程、函数、视图、数据修复),我想知道是否有共识关于什么是最佳做法?

我们需要考虑的一些因素包括:

  • 我们应该检入“创建”脚本还是使用“更改”脚本进行增量式检入
  • 如何跟踪给定发布版本的数据库状态
  • 对于任何给定版本的发布,从头开始构建数据库应该很容易
  • 是否应该存在一个表来列出已针对其运行的脚本或数据库版本等

显然这是个非常开放性的问题,所以我很想听听人们的经验教训。

12个回答

19

经过几次迭代,我们采取的方法大致如下:

每个表和存储过程都对应一个文件。此外,还有其他文件用于设置数据库用户、将查找表填充其数据等。

表的文件以 CREATE 命令开始,然后加入一系列 ALTER 命令,随着架构的演变逐步添加。其中每个命令都被放在针对表或列是否已存在的测试括号中。这意味着每个脚本可以在最新的数据库中运行,且不会改变任何内容。对于任何旧数据库,该脚本也会将其更新到最新的架构。对于空数据库,CREATE 脚本会创建表,而所有 ALTER 脚本则会被跳过。

我们还编写了一个程序(用 Python 编写),它扫描包含多个脚本的目录,并将它们组合成一个大型脚本。它对 SQL 进行了部分解析,以便根据外键引用之间的依赖性适当地排序表。结果是一个巨大的 SQL 脚本,可以一次性将数据库更新到规范版本。脚本组装程序还计算输入文件的 MD5 哈希值,并使用它来更新写入到列表中最后一个脚本中的特殊表中的版本号。

如果没有意外,这样做的结果是,给定源代码版本的数据库脚本将创建与该代码设计进行交互所需的架构。这也意味着只需要提供单个(略大)的 SQL 脚本即可让客户端建立新的数据库或更新现有的数据库。(在这种情况下,这很重要,因为将会有多个数据库实例,每个实例对应他们的一个客户端。)


3

2
您可以通过阅读 Ruby On Rails的迁移 如何完成此操作来获得一些提示。最好的方法可能是尝试自己操作,然后手动检查数据库。
各个因素的答案:
  • 存储CREATE脚本。如果您想要检出版本x.y.z,那么运行创建脚本以立即设置数据库会很好。您也可以添加ALTER脚本,以从上一个版本转换到下一个版本(例如,您提交了包含版本3 CREATE脚本和版本2→3 ALTER脚本的版本3)。
  • 参考Rails的迁移解决方案。基本上他们在数据库中保留表版本号,所以您始终知道。
  • 使用CREATE脚本。
  • 使用版本号可能是最通用的解决方案-脚本名称和路径随时间变化。
这是我的两分钱!

2

升级脚本选项

将每个更改作为单独的SQL脚本存储在数据库中。将每组更改存储在编号文件夹中。使用脚本逐个应用文件夹中的更改并记录已应用的文件夹。

优点: 完全自动化测试升级路径

缺点: 难以完整查看每个单独元素的历史记录 必须从头开始构建新的数据库版本


2
我倾向于在初始创建脚本中进行检查。然后我的数据库中有一个DbVersion表,我的代码使用它来升级数据库,如果有必要,就在初始连接时进行升级。例如,如果我的数据库版本是1,而我的代码版本是3,那么我的代码将应用ALTER语句将其升级到版本2,然后升级到版本3。我为此使用了一个简单的fallthrough switch语句。
这样做的好处是,当您部署应用程序的新版本时,它会自动升级旧数据库,您永远不必担心数据库与软件不同步。它还保持了非常明显的更改历史记录。
虽然这不适合所有软件,但可以应用各种变体。

1

我们在Subversion中创建一个分支,为下一个版本的所有数据库更改编写脚本并进行检查。 所有脚本都是可重复运行的,因此您可以多次运行它们而不会出错。

我们还将更改脚本链接到问题项或错误ID,以便在需要时可以保留更改集。 然后,我们有一个自动化构建过程,该过程查看我们要发布的问题项,并从Subversion中提取更改脚本,并创建一个带有所有更改的单个SQL脚本文件,并按适当的顺序进行排序。

然后使用此单个文件将更改推广到测试,QA和生产环境。 自动化构建过程还创建了记录版本(分支加构建ID)的数据库条目。 我们认为这是企业开发人员的最佳方法。 有关如何执行此操作的更多详细信息,请参见此处


0
每次发布时,我们需要提供一个update.sql文件,其中包含所有新表脚本、修改语句、新/修改的包、角色等。该文件用于将数据库从1版本升级到2版本。
无论我们在update.sql文件中包含什么,以上所有语句都需要分别放入各自的文件中。例如,修改语句必须作为新列添加到表中(表脚本必须被修改,而不是在文件中创建表脚本后添加Alter语句),新表、角色等也是如此。
因此,每当用户想要升级时,他将使用第一个update.sql文件进行升级。如果他想要从头开始构建,则将使用已经包含所有上述语句的build.sql文件,它可以使数据库保持同步。

sriRamulu Sriramis4u@yahoo.com


0

创建脚本选项:

使用创建脚本可以从头开始构建最新版本的数据库,该数据库除了默认查找数据外为空。

使用标准版本控制技术来存储、分支、标记版本和查看对象历史记录。

在升级实时数据库(不想丢失数据的情况下),请在新版本中创建一个空白的第二个数据库副本,并使用像Red-Gate的link text这样的工具。

优点: 文件更改以标准源代码方式进行跟踪

缺点: 依赖于手动使用第三方工具进行实际升级(没有/很少自动化)


0

我们公司之所以检查它们,只是因为有人决定将其放入某个SOX文件中。对我来说完全没有意义,除非可能作为参考文档。我看不出我们会在什么时候取出它们并尝试再次使用它们,如果我们这样做,我们必须知道哪一个先运行,哪一个后运行。备份数据库比保留Alter脚本更重要。


我相信它们只是从SOX文档的角度进行保留,这样你就有东西可以向审计员展示(如果他们询问)进行了什么更改。 - Brian Schmitt
1
当然,能够向自己展示所做的更改同样重要。 - Brett Hannah

0

如何是一个开放性问题

在我的情况下,我正在尝试创建一些简单易用的东西,以供开发人员使用,并按照以下方案进行:

我测试过的事情: 使用GitlabCI中的基于文件的脚本处理

  • 它不起作用,会创建冲突,如果出现灾难,管理部分必须手动完成,而开发部分则太复杂了

  • 使用权限和通过mysql客户端访问 没有关于数据库更改的可追溯性,而且转换到生产环境是手动的

  • 使用此处提到的程序 它们需要上传结构和许多适应性,通常最终会像Word一样进行更改控制

  • 仓库使用 无法控制DRP部分 我无法正确控制备份 我认为在同一服务器上备份并生成高日志对于该过程来说不是一个好主意

  • 这是最好的解决方案

  • 管理每个用户的权限并生成对发送到数据库的所有内容的可追溯性

  • 多平台

  • 使用开发-生产-QA数据库

  • 在每次修改之前始终提供支持

  • 管理用于变更控制的开放式存储库

  • 多服务器

  • 通过端点停用/启用对网页或应用程序的访问

  • 初始项目位于:

  • 如果评论管理员看到这部分,请移除自我推广的部分,只保留其余部分,因为我认为它符合帖子中所回答的问题... https://hub.docker.com/r/arelis/gitdb

我希望这条信息能够传达给您,因为我看到有几个...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接