版本控制数据库的正确策略
我正在阅读此博客,我对所写的5篇文章有疑问。据我所知,您在包含所有SQL DDL语句的大型基线脚本上创建。完成此操作后,您可以在单独的脚本中跟踪每个更改。
但是,我不明白脚本文件的名称如何与应用程序的特定版本相关联?他说,如果用户在3.1.5.6723中报告了一个错误,你可以将脚本重新运行到该版本。你会在自己的文件中跟踪对表等的更改,还是将所有DLL更改放在同一个脚本文件中,然后像他说的那样在自己的文件中具有视图等?
我正在阅读此博客,我对所写的5篇文章有疑问。据我所知,您在包含所有SQL DDL语句的大型基线脚本上创建。完成此操作后,您可以在单独的脚本中跟踪每个更改。
但是,我不明白脚本文件的名称如何与应用程序的特定版本相关联?他说,如果用户在3.1.5.6723中报告了一个错误,你可以将脚本重新运行到该版本。你会在自己的文件中跟踪对表等的更改,还是将所有DLL更改放在同一个脚本文件中,然后像他说的那样在自己的文件中具有视图等?
首先,数据库升级是邪恶的,但该博客描述了一场彻头彻尾的噩梦。
可以基于升级方法创建程序员能力矩阵:
我将描述所有技术问题,但在此之前,请允许我声明以下内容(请原谅我很长的答案):
级别 0 和级别 1这两种情况都是明显而愚蠢的。任何人都应该避免这种情况。
级别 2对于小桌子来说,改变并不是那么糟糕,但对于大桌子来说,这可能是一个问题。在非常大的表(>1Gb)上,ALTER TABLE可能需要几个小时甚至几天才能完成。此外,它确实只解决了模式升级问题,但是存储的数据呢?我还建议考虑物理数据布局,以了解这种方法背后的实际障碍。整个过程可能不安全,因此请确保您有备份。
解决 方案:
级别 3通过将架构移动到较高层,可以解决架构升级的问题。无模式解决方案在某种程度上受到限制,主要是因为它禁用了关系模型背后的全部功能。可以提出一种混合方法,既具有快速升级,又具有使用关系代数的能力。有一些有趣的文章:
请注意,升级过程的复杂性仍然存在,它只是转移到应用程序级别。有许多相关的场景,但我将描述一个我已经使用了几年的混合系统。我可以将数据模型描述为“具有关系的实体”。实体之间的关系在数据库级别表示,实体本身存储为 XML blob。
这个系统很成熟,有足够的客户。有很多功能请求,所以研发和QA团队有点压力。最初,升级过程是作为独立的 Java 应用程序实现的,从数据库读取 XML blob,使用 DOM API 对其进行升级并将其写回数据库。实际的方法看起来非常简单,但背后有几个隐藏的问题:
我试图通过使用更严格的升级过程定义,验证规则和CI系统对实际数据(在所有客户中收集)执行的广泛测试来减轻所有潜在风险。我很惊讶地看到一些步骤失败了,因为很久以前由旧的升级脚本引入了旧问题。为了解决隐藏的问题,开发了单独的升级步骤。还进行了一些优化,以将升级时间减少到合理的20-30分钟。基于控制台的进度条实现完成了其余的工作。
快速说明:任何最终用户都渴望看到任何长时间运行(>2 分钟)操作的进度。请不要忘记实现这样的“快乐”。
最初,数据库版本存储在单独的表中。请不要使用此方法,因为最好单独对实体进行版本控制,并避免在升级过程中锁定整个数据库。
将以一个升级过程为例(所有验证和验证步骤都隐藏在处理逻辑后面)。“-”表示更少,“*” - 任何构建<build/>
<version/>
<?xml version="1.0"?>
<upgrade>
<version name="-7.4">
<build name="*">
<script class="upgrade.version7.Replace...Script"/>
<script class="upgrade.version7.Update...Script"/>
<!-- 5 scripts skipped -->
</build>
</version>
<version name="-7.6">
<build name="*">
<script class="core.DatabaseUpdateVersion" version="7.6.48"/>
</build>
</version>
<version name="7.6">
<build name="*">
<script class="upgrade.version7.Update...Script"/>
<script class="core.DatabaseUpdateVersion" version="8.0.40"/>
<!-- 7 scripts skipped -->
</build>
</version>
<version name="8.0">
<build name="-53">... </build>
<build name="+52">... </build>
</version>
<version name="8.1">
<build name="-8"> ... </build>
<build name="-9">...</build>
<build name="-26">...</build>
<build name="-40">...</build>
<build name="-45">...</build>
<build name="-56">...</build>
<build name="-61">...</build>
<build name="-63">...</build>
<build name="-64">...</build>
<build name="-68">...</build>
<build name="-69">...</build>
<build name="-77">...</build>
<build name="-79">...</build>
<build name="-80">...</build>
<build name="-86">...</build>
<build name="-88">...</build>
<build name="-89"> ... </build>
</version>
<version name="8.2">...</version>
</upgrade>
每个脚本都是一个小的Java或Groovy实现(XSLT也被使用)。后来还开发了降级程序,但这是完全不同的故事。
级别 4应用层上的数据方案允许做很多有趣的事情。例如,可以用原型buf替换XML。像往常一样,这样做有几个原因(它更简单,更快等)。如果你不喜欢建筑商的概念,你可以使用节俭。
无论如何,protobuf允许创建一个向后兼容的系统(就存储的数据而言),几乎不费吹灰之力。顺便说一句,优势不错。通过向后兼容系统,您可以轻松实现延迟且完全透明的升级。它可以是后台进程或根据请求进行升级等。好消息是零停机时间,用户满意,并且能够更频繁地进行升级。这意味着您可以快速开发,及时响应客户的要求,换句话说,更成功。
级别 5抱歉,这次不行。请谨慎使用升级策略。出售一个定义了一些模式并将自己锁定在外的系统很容易。没有新功能 - 没有客户。
简单但非常有用的清单:
感谢您的阅读。