如何停止Rails 3.1迁移在事务中运行?

9
我想在生产数据库中添加索引。幸运的是,我们正在使用Postgres,它可以很好地支持并发索引,因此我们可以在不停机的情况下添加索引。但有一个问题-- 并发索引不能在事务内添加,而Rails迁移将所有内容都包装在事务中。

幸运的是,有一个看起来非常简单的解决方案:覆盖ActiveRecord :: Migration私有方法ddl_transaction,如这里所述。

class IndexUsersEmails < ActiveRecord::Migration
  def ddl_transaction(&block)
    block.call # do not start a transaction
  end

  def self.up
    execute "CREATE INDEX CONCURRENTLY index_users_on_email ON users(email)"
  end
end

问题在于它似乎无法在Rails 3.1中工作。我完全按照Gist中的代码操作,但Rails好像完全忽略了它。有什么想法吗?


你尝试过更改方法定义,使其成为类方法吗?例如:def self.ddl_transaction(&block) ... - Derek Harmel
2个回答

11

我刚刚注意到我从未在这里接受过答案,所以我应该说一下我的做法。结果发现你可以像这样退出交易:

class AddFbPageIdIndexToTabs < ActiveRecord::Migration
  def up
    execute "END"
    execute "CREATE INDEX CONCURRENTLY bob_lob_law_index ON bob_lob (law)"
    execute "BEGIN"
  end

  def down
    execute "END"
    execute "DROP INDEX CONCURRENTLY bob_lob_law_index"
    execute "BEGIN"
  end
end

在事务外部运行想要的代码之前,只需运行execute "END"。这会结束ActiveRecord::Migration为迁移自动设置的事务。在你完成想要在事务外运行的代码后,execute "BEGIN"开启一个新的事务,以便ActiveRecord::Migration可以进行清理过程并关闭它认为已打开的事务。

(我忘记在哪里找到这个技巧了,现在也找不到了。欢迎编辑来注明出处!)


1

我不是说这是“正确的方法”,但对我有效的是仅独立运行那一个迁移。

rake db:migrate:up VERSION=20120801151807

其中20120801151807是CREATE INDEX CONCURRENTLY迁移的时间戳。

显然,当您运行单个迁移时,它不使用事务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接