繁体   English   中英

你应该如何从源代码控制构建数据库?

[英]How should you build your database from source control?

关于数据库对象是否应该受版本控制的SO社区wiki已经有一些讨论。 但是, 我没有看到很多关于为数据库对象创建构建自动化过程的最佳实践的讨论。

这对我的团队来说是一个有争议的讨论点 - 特别是在评估数据库部署自动化方法的优势和风险时,开发人员和DBA通常有不同的目标,方法和关注点。

我想听听SO社区关于哪些实践在现实世界中有效的一些想法。

我意识到这有点主观,哪些实践真的是最好的,但我认为一个关于哪些工作可能对许多人有帮助的良好对话。

以下是我在此主题中关注领域的一些预告片问题。 这些并不是一个明确的清单 - 而是人们帮助理解我正在寻找的东西的起点。

  1. 测试和生产环境都应该从源代码控制构建吗?
    • 是应该使用自动化构建 - 还是应该通过从稳定的,最终的测试环境中复制对象来构建生产?
    • 您如何处理部署脚本中测试和生产环境之间的潜在差异?
    • 您如何测试部署脚本是否可以像测试一样有效地对抗生产?
  2. 哪些类型的对象应该受版本控制?
    • 只是代码(程序,包,触发器,java等)?
    • 指标?
    • 约束?
    • 表定义?
    • 表更改脚本? (例如,ALTER脚本)
    • 一切?
  3. 哪些类型的对象不应该受版本控制?
    • 序列?
    • 资助?
    • 用户帐户?
  4. 如何在SCM存储库中组织数据库对象?
    • 你如何处理转换脚本或ALTER脚本之类的一次性事务?
    • 你如何处理退出数据库中的对象?
    • 谁应该负责对象从开发推广到测试级别?
    • 如何协调来自多个开发人员的更改?
    • 您如何处理多个系统使用的数据库对象的分支?
  5. 如果有的话,可以合理地对这个过程做出哪些例外?
    • 安全问题?
    • 具有去识别问题的数据?
    • 脚本无法完全自动化?
  6. 如何使流程具有弹性和可执行性?
    • 开发者错误?
    • 出乎意料的环境问题?
    • 用于灾难恢复?
  7. 您如何让决策者相信DB-SCM的好处真正证明了成本的合理性?
    • 传闻?
    • 行业研究?
    • 行业最佳实践建议?
    • 向公认的当局上诉?
    • 成本效益分析?
  8. 谁应该在这个模型中“拥有”数据库对象?
    • 开发商?
    • 数据库管理员?
    • 数据分析师?
    • 超过一个?

以下是您的问题的一些答案:

  1. 测试和生产环境都应该从源代码控制构建吗?
    • 是应该使用自动化构建 - 还是应该通过从稳定的,最终的测试环境中复制对象来构建生产?
    • 两者的自动化。 不要在环境之间复制数据
    • 您如何处理部署脚本中测试和生产环境之间的潜在差异?
    • 使用模板,这样实际上您可以为每个环境生成不同的脚本集(例如,对外部系统,链接数据库等的引用)
    • 您如何测试部署脚本是否可以像测试一样有效地对抗生产?
    • 您在预生产环境中测试它们:在生产环境的精确副本上测试部署(数据库和可能的其他系统)
  2. 哪些类型的对象应该受版本控制?
    • 只是代码(程序,包,触发器,java等)?
    • 指标?
    • 约束?
    • 表定义?
    • 表更改脚本? (例如,ALTER脚本)
    • 一切?
    • 一切,和:
      • 不要忘记静态数据(查找列表等),因此您不需要在环境之间复制任何数据
      • 仅保留当前版本的数据库脚本(当然是受版本控制),以及
      • 存储ALTER脚本:1个BIG脚本(或命名为001_AlterXXX.sql的脚本目录,因此以自然排序顺序运行它们将从A版升级到B)
  3. 哪些类型的对象不应该受版本控制?
    • 序列?
    • 资助?
    • 用户帐户?
    • 请参阅2.如果您的用户/角色(或技术用户名)在不同环境之间有所不同,您仍然可以使用模板编写脚本(请参阅1.)
  4. 如何在SCM存储库中组织数据库对象?
    • 你如何处理转换脚本或ALTER脚本之类的一次性事务?
    • 见2。
    • 你如何处理退出数据库中的对象?
    • 从DB中删除,从源控制主干/提示中删除
    • 谁应该负责将对象从开发推广到测试级别?
    • 开发/测试/发布时间表
    • 如何协调来自多个开发人员的更改?
    • 尽量不为每个开发人员创建单独的数据库。 你使用源代码控制,对吗? 在这种情况下,开发人员更改数据库并签入脚本。 为了完全安全,在夜间构建期间从脚本重新创建数据库
    • 您如何处理多个系统使用的数据库对象的分支?
    • 艰难的一个:尽量避免不惜一切代价。
  5. 如果有的话,可以合理地对这个过程做出哪些例外?
    • 安全问题?
    • 不存储test / prod的密码。 你可以允许它开发,特别是如果你有自动每日/每晚数据库重建
    • 具有去识别问题的数据?
    • 脚本无法完全自动化?
    • 使用发布信息/ ALTER脚本记录和存储
  6. 如何使流程具有弹性和可执行性?
    • 开发者错误?
    • 从头开始测试每日构建,并将结果与​​增量升级进行比较(使用ALTER从版本A到B)。 比较结果模式和静态数据
    • 出乎意料的环境问题?
    • 使用版本控制和备份
    • 比较PROD数据库模式与您的想法,尤其是在部署之前。 SuperDuperCool DBA可能修复了票证系统中从未出现的错误:)
    • 用于灾难恢复?
  7. 您如何让决策者相信DB-SCM的好处真正证明了成本的合理性?
    • 传闻?
    • 行业研究?
    • 行业最佳实践建议?
    • 向公认的当局上诉?
    • 成本效益分析?
    • 如果开发人员和DBA同意,你不需要说服任何人,我想(除非你需要钱购买像dbSQL的MSGhost这样的软件)
  8. 谁应该在这个模型中“拥有”数据库对象?
    • 开发商?
    • 数据库管理员?
    • 数据分析师?
    • 超过一个?
    • 通常,DBA会批准该模型(在签入之前或作为代码审查的一部分之后)。 他们肯定拥有与性能相关的对象 但总的来说,团队拥有它[和雇主,当然:)]

我尽可能将SQL视为源代码

如果我可以在标准的兼容SQL中编写它,那么它通常会在我的源代码控制中的文件中。 该文件将尽可能多地定义,例如SP,表CREATE语句。

我还包括用于源代码控制测试的虚拟数据:

  1. 凸出/ SQL / setup_db.sql
  2. 凸出/ SQL / dummy_data.sql
  3. 凸出/ SQL / mssql_specific.sql
  4. 凸出/ SQL / mysql_specific.sql

然后我抽象出所有的SQL查询,以便我可以为MySQL,Oracle,MSSQL或其他任何东西构建整个项目。

构建和测试自动化使用这些构建脚本,因为它们与应用程序源一样重要,并测试从完整性到触发器,过程和日志记录的所有内容。

Liquibase的 +1: LiquiBase是一个开源(LGPL),独立于数据库的库,用于跟踪,管理和应用数据库更改。 它建立在一个简单的前提上:所有数据库更改(结构和数据)都以基于XML的描述方式存储,并检入源代码控制。 好的一点是,DML更改是在语义上存储的,而不仅仅是diff,因此您可以跟踪更改的目的。

它可以与GIT版本控制相结合,以实现更好的交互。 我将配置我们的dev-prod环境来试用它。

您还可以使用Maven,Ant构建系统从脚本构建生产代码。

减去的是LiquiBase没有集成到广泛的SQL IDE中,你应该自己做基本的操作。

除此之外 ,您还可以使用DBUnit进行数据库测试 - 此工具允许数据生成脚本用于测试您的生产环境并进行清理。

恕我直言:

  1. 将DML存储在文件中,以便对其进行版本控制。
  2. 从源代码控制自动化架构构建过程。
  3. 出于测试目的,开发人员可以使用通过构建系统从源代码控制构建的本地数据库+使用脚本或DBUnit脚本(来自源代码管理)的负载测试数据。
  4. LiquiBase允许您提供脚本的“运行顺序”以尊重依赖性。
  5. 在生产使用之前,应该有DBA团队在所有更改中检查主早午餐。 我的意思是他们在进入MASTER主干之前检查来自其他DBA的主干/分支。 因此,掌握始终是一致的,生产准备就绪。

我们在计费生产数据库中遇到了所有提到的代码更改,合并和重写问题。 这个主题非常适合发现所有这些内容。

我们通过TeamCity使用持续集成。 在每次签入源代码控制时,从头开始重新构建数据库和所有测试数据,然后是代码,然后针对代码运行单元测试。 如果您正在使用像CodeSmith这样的代码生成工具,它也可以放入您的构建过程中,以便在每次构建时生成新的数据访问层,确保所有层“匹配”并且不会因为SP参数不匹配或缺少列。

每个构建都有自己的SQL脚本集合,这些脚本存储在源代码管理的$ project \\ SQL \\目录中,分配了一个数字前缀并按顺序执行。 这样,我们就会在每次构建时练习我们的部署过程。

根据查找表,我们的大多数查找值也存储在脚本中并运行以确保配置数据符合我们的预期,例如“reason_codes”或“country_codes”。 这样我们就可以在开发中进行查找数据更改,测试它然后通过QA和生产“提升”它,而不是使用工具来修改生产中的查找值,这对正常运行时间来说是危险的。

我们还创建了一组“回滚”脚本来撤消我们的数据库更改,以防生产构建变得棘手。 您可以通过运行它们来测试回滚脚本,然后在部署脚本运行后重新运行低于您的版本的单元测试。

我基本同意van给出的每一个答案。 更深入的了解,我的数据库管理基准是K. Scott Allen系列 (必读,恕我直言。而且看来Jeff也是如此)。

  • 通过启动单个SQL文件(本身可以调用其他SQL文件),可以始终从头开始重建数据库对象: Create.sql 这可以包括静态数据插入(列表......)。
  • SQL脚本已参数化,因此不会在纯文件中存储依赖于环境的和/或敏感信息。
  • 我使用自定义批处理文件来启动Create.sqlCreate.cmd 它的目标主要是检查先决条件(工具,环境变量......)并将参数发送到SQL脚本。 它还可以批量加载 CSV文件中的静态数据,以解决性能问题。
  • 通常,系统用户凭据将作为参数传递给Create.cmd文件。

恕我直言, 动态数据加载应该需要另一个步骤,具体取决于您的环境。 开发人员希望根据测试,垃圾或无数据加载他们的数据库,而在另一端,生产经理将希望加载生产数据。 我也会考虑将测试数据存储在源代码控制中(例如,为了简化单元测试)。

一旦数据库的第一个版本投入生产,您不仅需要构建脚本(主要用于开发人员),还需要升级脚本(基于相同的原则):

  • 必须有一种方法从数据库中检索版本(我使用存储过程,但表也可以)。
  • 在发布新版本之前,我创建了一个Upgrade.sql文件(可以调用其他文件),允许将版本N-1升级到版本N(N是正在发布的版本)。 我将此脚本存储在名为N-1的文件夹下。
  • 我有一个进行升级的批处理文件: Upgrade.cmd 它可以通过简单的SELECT语句检索数据库的当前版本(CV),启动存储在CV文件夹下的Upgrade.sql脚本,然后循环直到找不到文件夹。 这样,您可以自动从N-3升级到N.

这个问题是:

  • 根据数据库供应商的说法,很难自动比较数据库模式。 这可能导致升级脚本不完整。
  • 对生产环境的每次更改(通常由DBA进行性能调整)也应该找到源代码控制的方式。 为了确保这一点,通常可以通过触发器记录对数据库的每个修改。 每次升级后都会重置此日志。
  • 但更理想的是,DBA发起的更改应尽可能是发布/升级过程的一部分。

至于您希望在源代码管理下拥有哪种数据库对象? 好吧,我会尽可能地说,但不是更多;-)如果你想用密码创建用户,给他们一个默认密码(登录/登录,实用于单元测试目的),并使密码更改为手动操作。 这种情况在Oracle中发生很多,其中模式也是用户...

通过询问“预告片问题”,您似乎对某个讨论更感兴趣,而不是某人对最终答案的看法。 活跃的(> 2500个成员)邮件列表agileDatabases解决了许多这些问题,根据我的经验,这是一个用于此类讨论的复杂而民用的论坛。

而不是进入白塔争论,这是一个解决方案,对我来说在现实世界问题上非常有效。

从头开始构建数据库可以概括为管理sql脚本。

DBdeploy是一个检查数据库当前状态的工具 - 例如,之前运行过哪些脚本,可以运行哪些脚本,以及需要运行哪些脚本。

然后它会将所有需要的脚本整理在一起并运行它们。 然后它记录已运行的脚本。

它不是最漂亮的工具或最复杂的工具 - 但通过精心管理,它可以很好地工作。 它是开源的,易于扩展。 一旦很好地处理了脚本的运行,就可以轻松地添加一些额外的组件,例如shell脚本,它可以检查最新的脚本并针对特定实例运行dbdeploy。

在这里看一个很好的介绍:

http://code.google.com/p/dbdeploy/wiki/GettingStarted

我们在Git版本控制中使用带有MSSQL数据库的Silverlight项目。 最简单的方法是确保你有一个精简的数据库(内容明智),并从fe Visual Studio 完成转储。 然后,您可以从构建脚本执行'sqlcmd',以在每台开发机器上重新创建数据库。

对于部署,这是不可能的,因为数据库太大:这是将它们放在数据库中的主要原因。

我坚信DB应该是源代码控制的一部分,并且在很大程度上是构建过程的一部分。 如果它在源代码控制中,那么在SQL中编写存储过程时,我就像在C#中编写类时一样,具有相同的编码安全保护。 我通过在源代码树下包含一个DB脚本目录来完成此操作。 此脚本目录不一定有一个文件用于数据库中的一个对象。 这将是一个痛苦的屁股! 我在我的数据库中开发只是我想在我的代码项目中。 然后当我准备好检查时,我在我的数据库的最后一个版本和我正在处理的当前版本之间做了一个差异。 我为此使用SQL Compare,它会生成所有更改的脚本。 然后将此脚本保存到我的db_update目录,其中包含特定的命名约定1234_TasksCompletedInThisIteration,其中该数字是已存在的脚本集中的下一个数字,名称描述了此检查中正在执行的操作。我这样做是因为as我的构建过程的一部分,我从一个新的数据库开始,然后使用此目录中的脚本以编程方式构建。 我编写了一个自定义的NAnt任务,它遍历在裸db上执行其内容的每个脚本。 显然,如果我需要一些数据进入数据库,那么我也有数据插入脚本。 这也有很多好处。 一,我所有的东西都是版本的。 二,每个构建都是一个新构建,这意味着不会有任何偷偷摸摸的东西进入我的开发过程(例如导致系统奇怪的脏数据)。 三,当一个新人被添加到开发团队时,他们只需要获得最新信息,他们的本地开发人员即可为他们构建。 四,我可以在我的数据库上运行测试用例(我没有把它称为“单元测试”!),因为每次构建都会重置数据库的状态(这意味着我可以测试我的存储库而不必担心将测试数据添加到D b)。

这不适合所有人。

这不适用于每个项目。 我经常在绿色的田野项目上工作,这让我很方便!

您可能会发现Liquibase处理了很多您正在寻找的东西。

每个开发人员都应该拥有自己的本地数据库,并使用源代码控制来发布给团队。 我的解决方案在这里: http//dbsourcetools.codeplex.com/玩得开心, - Nathan

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM