新手问题 关于生产环境数据库迁移正确姿势的问题

stevefan · 2015年05月25日 · 最后由 stevefan 回复于 2015年05月29日 · 3241 次阅读

需求描述

目前有一张表(clients)中,想把该表的一个字段(title)分离出来,新建一张表(programs),programs 表中包含 title 字段,然后在 clients 表中添加 program_id 外键。

数据库模式迁移:

  1. 新建 program model,(rails g model program title:string
  2. 添加外键 program_id 到 clients, (add_references :clients, :program
  3. 删除 clients 表中的 ttile 字段,(remove_column :clients, :title

问题

问题在于,在生成环境中,这张表已经有大量数据存在,如果直接 db:migrate 估计 clients 表中的 title 字段的数据会全部丢失。

我的解决方案

  1. 添加 rake task,根据 Client.select(:title).distinct 的查询结果,填充 program 记录。
  2. 在数据库模式迁移过程的第一步后执行上述 rake task。

请教

  • 不知该姿势是否正确?
  • 其他更好的姿势?

在迁移文件中写数据迁移逻辑。

改删除为 rename,等过一段时间确认没有问题再删除

楼上两位的回答 + 1 另外可以在 Client 里 delegate :title, to: :program, prefix: false

如果数据量大,可以用 rails db 直接写 sql 语句,比 rake 中写 ruby 减少了网络 IO 传输的开销,节省的大量的时间及减少了程序跑一半意外挂掉的风险

migration 中是可以写 ruby 代码的

例如这样:

class AddKeyToUsers < ActiveRecord::Migration

  def self.up
    add_column :users, :key, :string, null: false

    User.find_each do |user|
      if user.key.blank?
        user.key = SecureRandom.hex
        user.save(validate: false)
      end
    end

    add_index :users, :key, uniqueue: true
  end

  def self.down
    remove_index :users, :key
    remove_column :users, :key
  end

end

这种方式的缺点是中间那段 ruby 代码导致异常时,migration 就中断了,重新 migrate 的时候得注释一些东西。 好处是逻辑简单明了,不用头疼这些一次性代码往哪里放

@rei @azhao @leekelby @cuihq @qhwa @hooopo

感谢大家的关注和回复。

综合比较之后,我最终使用 rake task 来迁移(修复)数据,同时采用了 @azhao 的建议,先保留 title 的数据,待确认数据迁移无误之后,才删除该字段。

生产环境的数据量不大,所以数据迁移过程中没有使用 sql,谢谢 @cuihq 的 tips。 @hooopo 的提供的帖子很受用,谢谢。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号