【问题标题】:When (if) to consolidate ActiveRecord migrations?何时(如果)合并 ActiveRecord 迁移?
【发布时间】:2010-12-01 23:20:29
【问题描述】:

当我在我的应用程序上进行迭代时*(s) 我积累了迁移。截至目前,共有 48 个此类文件,活动时间约为 24 个月。

我正在考虑以我目前的schema.rb 为基准。

我也在考虑删除(当然,受源代码控制)现有迁移并从我当前的架构创建一个漂亮的闪亮的新单一迁移?迁移倾向于喜欢符号,但rake db:schema:dump 使用字符串:我应该在意吗?

这看起来合理吗? 如果是这样,这样的练习在什么样的时间间隔才有意义? 如果没有,为什么不呢?

我是否错过了一些可以为我做这件事的(耙子?)任务?

* 就我而言,所有应用程序都是基于 Rails 的,但任何使用 ActiveRecord 迁移的东西似乎都适合这个问题。

【问题讨论】:

标签: ruby-on-rails ruby activerecord migration


【解决方案1】:

我认为有两种迁移:

  • 那些你在设计/开发过程中所做的,因为你改变了你的数据库应该是什么样子的想法;

  • 您在发布之间所做的那些,反映了一些行为变化。

我会尽快摆脱第一种迁移,因为它们并不真正代表工作版本,并保留第二种迁移,以便理论上可以更新应用程序。

关于符号与字符串:许多人认为在迁移中只应使用字符串:符号旨在作为对象的“句柄”,而不应用于表示名称(在这种情况下为列名和表名)。这只是一种风格上的考虑,但说服了我,我不再在迁移中使用符号。

我读过关于使用字符串的另一点:“ruby 符号是内存泄漏”,这意味着,当您创建一个符号时,它在整个应用程序生命周期内都不会被释放。这对我来说似乎毫无意义,因为您的所有 db 列都将用作 Rails(和 ActiveRecord)应用程序中的符号;迁移任务也不会永远持续下去,所以我认为这一点实际上没有意义。

【讨论】:

  • 只是一个关于符号/字符串的随机注释:如果一个符号被使用 10 次,它只占用一次内存。当使用字符串时(假设是文字字符串),它每次在代码中都会占用所需的内存。所以这个符号可能永远不会被 GC 处理,周围只有一个。
【解决方案2】:

您不应该删除迁移。为什么要创建额外的工作?

迁移本质上是一组指令,用于定义如何构建数据库以支持您的应用程序。在您构建应用程序时,迁移会记录您对数据库所做的迭代更改。

恕我直言,通过定期重置基线,您所做的更改可能会给您的应用程序带来错误/问题,从而产生额外的工作。

如果一个列被错误地添加,然后需要稍后删除,只需创建一个新的迁移以删除额外的列。我这样做的主要原因是,在团队中工作时,您不希望您的同事不得不从头开始重建他们的数据库。通过这种简单的方法,您(和他们)可以以迭代方式继续工作。

顺便说一句 - 从头开始​​构建新数据库(没有任何数据)时,迁移往往运行得非常快。我目前正在进行的一个项目有 177 次迁移,这在构建新数据库时不会出现问题。

【讨论】:

    【解决方案3】:

    虽然我确信每个人都有自己的做法,但迁移系统的工作方式隐含着一些规则:

    • 切勿对可能已被其他开发人员或先前部署使用的迁移提交更改。相反,请进行额外的迁移以根据需要进行调整。
    • 切勿将模型级依赖项放入迁移中。该模型可能会在将来的某个时候被重命名或删除,这将阻止迁移。尽可能保持迁移自包含,即使这意味着它非常简单和低级。

    当然也有例外。例如,如果迁移不起作用,无论出于何种原因,都可能需要一个补丁来更新它。尽管如此,迁移所产生的变化的性质不应该改变,尽管它们的实现可能会改变。

    任何成熟的 Rails 项目都可能有大约 200 到 1000 次迁移。以我的经验,除了在规划阶段之外,看到一个少于 30 个的项目是不寻常的。毕竟,每个模型通常都需要自己的迁移文件。

    在开发不断发展的软件时,将多个迁移合并为一个是一个坏习惯。您可能不会折叠源代码控制历史记录,那么为什么还要担心数据库架构历史记录呢?

    我认为它比较实用的唯一情况是,如果您要分叉旧项目以创建新版本或衍生产品,并且不想进行大量迁移。

    【讨论】:

    • 一个具有一定复杂性的成熟项目可能已经经历了一个或多个重要的数据库重构,迁移会“调整”事物以支持每个重构。随着时间的推移,当从头到尾直接运行所有迁移时,这些与重构相关的迁移可能会出现问题。在这些情况下,折叠较旧的迁移具有潜在的优势。
    • 如果您遇到“太多”迁移的情况,您可以随时将它们全部折叠到当前db/schema.rb 的快照中。请记住,成熟的项目通常需要自定义数据库快照,因此从头开始迁移的人数应该最少。除非您确实有成千上万的迁移,否则可能不值得重写历史。它通常会产生意想不到的副作用。
    【解决方案4】:

    是的,这是有道理的。有一种合并迁移的做法。为此,只需将当前架构复制到迁移中,然后删除所有早期迁移。这样您就可以管理更少的文件,并且测试可以运行得更快。 您需要小心执行此操作,尤其是当您在生产环境中自动运行迁移时。我通常用新模式替换我知道每个人都运行过的迁移。

    其他人的做法略有不同。

    在我们进行超过 100 次迁移之前,我通常不会这样做,但我们可以在几个月的开发后实现这一目标。但是,随着项目的成熟,迁移的频率越来越低,因此您可能不必再做一次。

    这确实违反了最佳做法:一旦您签入到源代码管理的迁移,就不要更改它。如果其中有一个错误,我会做一个罕见的例外,但这非常罕见(可能是 100 个中的 1 个)。原因是一旦它们在野外出现,有些人可能已经运行它们了。它们被记录为在数据库中完成。如果您更改它们并签入新版本,其他人将无法从更改中受益。您可以要求人们回滚某些更改并重新运行它们,但这违背了自动化的目的。经常做,就会变得一团糟。最好不要管。

    【讨论】:

    • 因此,例如,一旦我将迁移运行到生产环境,我为什么要继续运行旧的迁移?例如,要为新的开发/测试环境设置新数据库,我应该只 db:schema:load 到基线,然后运行新的迁移。这似乎是明智的。毕竟,我将始终在旧源版本中进行原始迁移。
    • 我们的自动化测试环境执行 db:reset 并在每组测试之前运行所有迁移,这实际上是迁移完全运行的唯一一次,重做迁移很有帮助。人们清理它们只是为了减少文件的数量。当然 db:schema:load 会起作用...我认为它背后的想法是您可以对迁移进行一些测试,作为持续集成的一部分。
    【解决方案5】:

    schema.rb 顶部声明:

    # This file is auto-generated from the current state of the database. Instead of editing this file, 
    # please use the migrations feature of Active Record to incrementally modify your database, and
    # then regenerate this schema definition.
    #
    # Note that this schema.rb definition is the authoritative source for your database schema. If you need
    # to create the application database on another system, you should be using db:schema:load, not running
    # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
    # you'll amass, the slower it'll run and the greater likelihood for issues).
    #
    # It's strongly recommended to check this file into your version control system.
    

    我必须赞同 [giorgian] 上面所说的关于不同目的的不同迁移。我建议清理面向开发的迁移以及在分支发布时执行的其他任务。这对我、我自己和小团队都很有效。当然,我的主应用程序位于其他两个具有自己架构的数据库之上和之间,我必须小心这些架构,因此我们使用迁移(而不是架构还原)进行新安装,并且那些需要在发布工程中幸存下来。

    【讨论】:

      【解决方案6】:

      进行大量迁移是一件好事。结合您的版本控制系统,它们允许您查看哪些开发人员对数据库进行了更改以及原因。这有助于问责制。删除它们只会让这变得很麻烦。

      如果您真的想快速启动并运行一个新数据库,您可以使用 rake db:schema:load RAILS_ENV=your_environment 加载架构,如果您想快速设置测试数据库,您可以使用 rake db:测试:准备

      话虽如此,如果您真的想整合您的迁移,那么我会创建一个新迁移来检查您的集合中的最后一个迁移是否已执行(例如:您添加的列是否存在?)和如果没有,那么它会开火。否则,迁移只会将自身添加到已完成的架构表中,因此不会再次尝试触发。

      只需将您正在做的事情传达给团队的其他成员,以便他们了解正在发生的事情,以免他们盲目地启动 rake db:migrate 并搞砸他们已经拥有的东西。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多