如何改变某个表的列的类型,生成一个迁移

98 阅读2分钟

当你需要改变Materialized View所使用的某个表的列的类型时,会发生什么情况。你是如何做到这一点的?假设你想把products.namestring 改为text ,你需要生成一个迁移。

rails g migration change_products_name

有以下内容。

class ChangeProductsName < ActiveRecord::Migration
  def up
    drop_view :expensive_products, materialized: true

    change_column :products, :name, :text

    create_view :expensive_products, materialized: true

    # If we had more versions for this materialized we would use the latest
    # generated instruction, something like:
    #
    # update_view :expensive_products, version: 2, revert_to_version: 1, materialized: true

    add_index :expensive_products, :id, unique: true
  end

  def down
    drop_view :expensive_products, materialized: true

    change_column :products, :name, :string

    create_view :expensive_products, materialized: true

    # Similar to "#up" we would do the same:
    #
    # update_view :expensive_products, version: 2, revert_to_version: 1, materialized: true

    add_index :expensive_products, :id, unique: true
  end
end

从这个迁移的代码中可以看出,重要的是我们如何进行修改以更新表,然后,在这之后,我们创建或更新物化视图,取决于我们已经有多少个版本。

关于这一切的重要问题是。这是正确的方法吗?如果你没有真正的实时流量,或者你不介意在数据库进行修改的时候出现错误,这绝对是一个好方法。

当你的系统有大量的流量时,你需要小心并尊重你的客户,对我来说,处理这样的变化的最好方法是做以下事情。

  1. 创建一个单一的迁移,在表中添加一个具有你想使用的正确类型的新列。
  2. 创建一个dumpsterrake任务,将数据从旧列复制到新列。
  3. 更新你的视图,如果有的话,以使用这个新列。
  4. 创建一个新的物化视图,使用这个新列而不是其他列。
  5. 更新你的模型和self.table_name到这个新的物化视图。
  6. 进行发布
  7. 创建一个与上面类似的迁移,做一些你想要的改变。
  8. 再次,创建一个dumpsterrake任务,在这种情况下,将数据从新列复制到旧列。
  9. 再次,更新你的视图,如果有的话,以使用旧的列。
  10. 再次,更新你的模型以使用旧的self.table_name
  11. 进行发布

我知道上面所有的步骤看起来都是多余的,但事实是,如果你想让你的系统保持100%的正常运行时间,错误和用户投诉的数量几乎为零,这基本上是唯一的办法了。