代码之家  ›  专栏  ›  技术社区  ›  Yann Ramin

您应该如何从源代码管理构建数据库?

  •  102
  • Yann Ramin  · 技术社区  · 7 年前

    关于数据库对象是否应该进行版本控制,SO社区wiki上进行了一些讨论。然而 关于为数据库对象创建构建自动化过程的最佳实践,我没有看到太多的讨论。

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

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

    以下是我关于本主题关注领域的一些挑逗性问题。这些并不是一个确定的列表,而是人们帮助理解我在寻找什么的起点。


      • 两者都应该使用自动化构建,还是应该通过从稳定、最终的测试环境复制对象来构建生产?
      • 如何在部署脚本中处理测试环境和生产环境之间的潜在差异?
      • 您如何测试部署脚本在生产环境中的工作效率是否和在测试中一样高?
      • 仅仅是代码(过程、包、触发器、java等)?
      • 索引?
      • 约束条件?
      • 表更改脚本?(例如改变脚本)
      • 每件事
    1. 哪些类型的对象不应进行版本控制?
      • 用户帐户?
    2. 如何在SCM存储库中组织数据库对象?
      • 如何处理转换脚本或更改脚本之类的一次性事件?
      • 如何处理从数据库中注销对象?
      • 谁应该负责 促进 从开发到测试级别的对象?
      • 如何协调来自多个开发人员的更改?
      • 如何处理多个系统使用的数据库对象的分支?
      • 有取消识别问题的数据?
      • 不能完全自动化的脚本?
      • 开发人员错误?
      • 意外的环境问题?
      • 用于灾难恢复?
    3. 您如何使决策者相信DB-SCM的好处确实证明了成本的合理性?
      • 行业研究?
      • 行业最佳实践建议?
      • 向认可当局上诉?
      • 成本/效益分析?
    4. 在此模型中谁应该“拥有”数据库对象?
      • 开发者?
      • DBA?
      • 不止一个?
    11 回复  |  直到 17 年前
        1
  •  54
  •   TSK    9 年前

    以下是对您的问题的一些回答:

    1. 测试和生产环境是否都应该从源代码管理构建? 对
      • 两者都应该使用自动化构建,还是应该通过从稳定、最终的测试环境复制对象来构建生产?
      • 两者的自动化。不要在环境之间复制数据
      • 如何在部署脚本中处理测试环境和生产环境之间的潜在差异?
      • 使用模板,以便实际为每个环境生成不同的脚本集(例如对外部系统、链接数据库等的引用)
      • 您如何测试部署脚本在生产环境中的工作效率是否和在测试中一样高?
      • 您可以在预生产环境中测试它们:在生产环境(数据库和可能的其他系统)的精确副本上测试部署
    2. 什么类型的对象应该进行版本控制?
      • 索引?
      • 约束条件?
      • 表格定义?
      • 表更改脚本?(例如改变脚本)
      • 每件事
        • 不要忘记静态数据(查找列表等),因此不需要在环境之间复制任何数据
        • 仅保留数据库脚本的当前版本(当然,版本受控),以及
        • 存储ALTER脚本:1个大脚本(或名为001_AlterXXX.sql的脚本目录,以便按自然排序顺序运行它们将从版本A升级到版本B)
      • 序列?
      • 赠款?
      • 用户帐户?
      • 见第2条。如果您的用户/角色(或技术用户名)在不同的环境中不同,您仍然可以使用模板为其编写脚本(请参见1)
      • 如何处理转换脚本或更改脚本之类的一次性事件?
      • 见第2条。
      • 谁应该负责将对象从开发提升到测试级别?
      • 开发/测试/发布时间表
      • 如何协调来自多个开发人员的更改?
      • 尽量不要为每个开发人员创建单独的数据库。您使用源代码管理,对吗?在这种情况下,开发人员更改数据库并签入脚本。为了完全安全,在夜间构建期间从脚本重新创建数据库
      • 如何处理多个系统使用的数据库对象的分支?
      • 艰难的一点:不惜一切代价避免。
    3. 对于该过程,有哪些例外情况(如有)是合理的?
      • 安全问题?
      • 不要为测试/生产存储密码。您可以为开发人员使用该密码,尤其是在您每天/每夜自动重建数据库的情况下
      • 有取消识别问题的数据?
      • 不能完全自动化的脚本?
      • 使用发布信息/ALTER脚本记录和存储
    4. 如何使流程具有弹性和可执行性?
      • 开发人员错误?
      • 使用每日从头构建进行测试,并将结果与增量升级(使用ALTER从版本A升级到版本B)进行比较。比较结果模式和静态数据
      • 意外的环境问题?
      • 使用版本控制和备份
      • 将PROD数据库模式与您认为的模式进行比较,尤其是在部署之前。SuperDuperCool DBA可能已修复了票证系统中从未出现过的错误:)
      • 用于灾难恢复?
    5. 您如何使决策者相信DB-SCM的好处确实证明了成本的合理性?
      • 轶事证据?
      • 行业研究?
      • 行业最佳实践建议?
      • 向认可当局上诉?
      • 成本/效益分析?
      • 如果开发人员和DBA同意,我认为您不需要说服任何人(除非您需要钱来购买像 dbGhost (适用于MSSQL)
      • 开发者?
      • DBA?
      • 数据分析师?
      • 通常DBA批准模型(在签入之前或之后,作为代码审查的一部分)。他们肯定拥有与性能相关的对象。但一般来说,团队拥有它[当然还有雇主:)]
        2
  •  5
  •   Aiden Bell    17 年前

    如果可能的话,我会将SQL视为源代码

    如果我能用英文写的话 然后,它通常放在我的源代码管理中的一个文件中。该文件将尽可能多地定义SPs、Table CREATE语句等。

    我还包括源代码管理中测试的虚拟数据:

    1. proj/sql/setup\u db.sql
    2. proj/sql/dummy_data.sql
    3. proj/sql/mssql_specific.sql
    4. proj/sql/mysql\u specific.sql

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

    它们与应用程序源一样重要 并测试从完整性到触发器、过程和日志记录的所有内容。

        3
  •  4
  •   Chris McCall    17 年前

    我们通过TeamCity进行持续集成。在每次签入源代码管理时,数据库和所有测试数据都会从头开始重新构建,然后是代码,然后针对代码运行单元测试。如果您使用的是CodeSmith之类的代码生成工具,还可以将其放入构建过程中,以生成每个构建的新数据访问层,确保所有层“匹配”,并且不会因SP参数不匹配或缺少列而产生错误。

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

    根据查找表的不同,我们的大多数查找值也存储在脚本中,并运行以确保配置数据符合我们的预期,例如“原因代码”或“国家代码”。通过这种方式,我们可以在dev中更改查找数据,对其进行测试,然后通过QA和生产“升级”,而不是在生产中使用工具修改查找值,这可能会对正常运行时间造成危险。

    我们还创建了一组“回滚”脚本,这些脚本可以撤消数据库更改,以防生产构建出错。您可以通过运行回滚脚本来测试回滚脚本,然后在部署脚本运行后,为您的构建版本下的构建版本重新运行单元测试。

        4
  •  4
  •   zmische    13 年前

    +1为 液化 LiquiBase 好的一点是,DML更改是以语义存储的,而不仅仅是diff,这样您就可以跟踪更改的目的。

    GIT 版本控制以实现更好的交互。我将配置我们的dev-prod环境来进行尝试。

    你也可以用 马文,蚂蚁 构建用于从脚本生成生产代码的系统。

    缺点是LiquiBase不能集成到广泛使用的SQLIDE中,您应该自己完成基本操作。

    DBUnit 对于DB测试-此工具允许使用数据生成脚本使用cleanup Afterwards测试生产环境。

    IMHO:

    1. 将DML存储在文件中,以便 版本。
    2. 从中自动化架构构建过程 源头控制。
    3. 出于测试目的,开发人员可以 通过构建系统进行源代码控制+ 使用脚本加载测试数据,或 DBUnit脚本(来自源代码) 控制)。
    4. LiquiBase允许您提供“run” 要尊重的脚本的“顺序” 家属。
    5. 全变早午餐 检查来自其他DBA的中继/分支 在提交到主中继之前。 所以主人总是始终如一的

    我们在计费产品数据库中遇到了所有提到的代码更改、合并和重写问题。这个主题对于发现所有这些东西都很有帮助。

        5
  •  3
  •   Glenn    17 年前

    agileDatabases 已经解决了许多这些问题,并且以我的经验来看,它是一个进行此类讨论的成熟和民间论坛。

        6
  •  3
  •   Jason Gritman    7 年前

    我基本上同意他给出的每一个答案 van . 为了更深入地了解,我的数据库管理基线是 K. Scott Allen series (a)必须阅读,IMHO.和 Jeff's opinion 似乎也是如此)。

    • Create.sql . 这可以包括 静止的 数据插入(列表…)。
    • 我使用自定义批处理文件启动 Create.sql : Create.cmd 散装货物 性能问题CSV文件中的静态数据。
    • 通常,系统用户凭据将作为参数传递给 文件

    依我拙见 数据加载需要另一个步骤,具体取决于您的环境。开发人员希望用测试数据、垃圾数据或根本没有数据加载他们的数据库,而在另一端,生产经理希望加载生产数据。我会考虑在源代码管理中存储测试数据(例如,简化单元测试)。

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

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

    这方面的问题有:

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

    您希望在源代码管理下拥有什么样的数据库对象?好吧,我会说尽可能多,但不要更多;-)如果要创建具有密码的用户,请为他们获取默认密码(登录/登录,适用于单元测试目的),并将密码更改设置为手动操作。这在Oracle中经常发生,其中模式也是用户。。。

        7
  •  1
  •   Rutger Nijlunsing    17 年前

    我们的Silverlight项目在Git版本控制中使用MSSQL数据库。最简单的方法是确保您有一个精简的数据库(内容方面),并执行以下操作: 完成

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

        8
  •  1
  •   Andrew Siemer    17 年前

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

    这不适合所有人。

    这并非适用于所有项目。我通常在绿地项目上工作,这让我很方便!

        9
  •  1
  •   Pablojim    17 年前

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

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

    数据库部署 是一种检查数据库当前状态的工具,例如,以前针对数据库运行过哪些脚本,可以运行哪些脚本,因此需要运行哪些脚本。

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

    它不是最漂亮的工具,也不是最复杂的工具,但如果管理得当,它可以很好地工作。它是开源的,易于扩展。一旦脚本的运行得到了很好的处理,添加一些额外的组件(比如一个shell脚本)就很容易实现了,该脚本可以签出最新的脚本并针对特定实例运行dbdeploy。

    这里有一个很好的介绍:

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

        10
  •  0
  •   David Plumpton    17 年前

    你可能会发现 Liquibase 处理很多你想要的东西。

        11
  •  0
  •   Nathan Rozentals    17 年前

    每个开发人员都应该有自己的本地数据库,并使用源代码控制向团队发布。我的解决方案是: http://dbsourcetools.codeplex.com/ 玩得高兴 -内森