Today I Learned

This project exists to catalogue the sharing & accumulation of knowledge as it happens day-to-day. Posts have a 200-word limit, and posting is open to any Rocketeer as well as selected friends of JetRockets. We hope you enjoy learning along with us.

How to add index to a large working app on Rails?

Well known fact is that PostgreSQL and many other RDBMS lock write access on the table while the index is being created. It is not acceptable when your project is large enough to allow a downtime for such the small adjustment like a new index. There is a way to avoid the write-lock though. You can create the index concurrently. But how to do it with Rails Migrations? First of all you can pass :algorithm option:

class AddIndexOnBatchIdToFundTrades < ActiveRecord::Migration[5.0]
  def change
    add_index :fund_trades, :batch_id, algorithm: :concurrently
  end
end

But when you try to run such the migration, you would get the following error:

PG::ActiveSqlTransaction: ERROR:  CREATE INDEX CONCURRENTLY cannot run inside a transaction block
: CREATE  INDEX CONCURRENTLY "index_fund_trades_on_batch_id" ON "fund_trades"  ("batch_id")

That’s because any migration by default is executed inside a transaction. Thankfully there is a way to pass it through - use disable_ddl_transaction! to run your migration without a transaction:

class AddIndexOnBatchIdToFundTrades < ActiveRecord::Migration[5.0]
  disable_ddl_transaction!

  def change
    add_index :fund_trades, :batch_id, algorithm: :concurrently
  end
end
Looking for help? JetRockets has been an leader in Ruby on Rails since 2012. Rails is a core skill for each developer at JetRockets and we'd love to take a look at your project. Contact us and find out how we can help you.