一から勉強させてください

最下級エンジニアが日々の学びをアウトプットしていくだけのブログです

RailsのマイグレーションでPostgreSQLのCREATE INDEX CONCURRENTLYする

最近、PostgreSQL を使用している Rails プロジェクトでCREATE INDEX CONCURRENTLYする機会があったのでメモ。

CREATE INDEX CONCURRENTLY とは

通常のインデックス作成処理では、処理が完了するまで対象テーブルへの書き込みはロックされる(読み取りはロックされない)。

そしてテーブルのレコードが大量にある場合、インデックス作成に数時間かかることも考えられるので、その間ずっと書き込みがロックされるのはツラい。

PostgreSQLCREATE INDEXCONCURRENTLYというオプションをサポートしており、書き込みのロックを行わずにインデックスを作成することが可能。

ただし、これはサービスのダウンタイムが回避できる代わりに、通常よりも処理に時間がかかり、負荷も上がることが考えられる。

またここでは CREATE INDEX CONCURRENTLYが実際どのようにワークするのかといったことには言及しない (知らん)ので、そういった所に興味のある方はこちらのような記事を読むのが良いと思います。

Railsマイグレーションで実行する

こんな感じで指定できる:

class AddIndexToUsersActive < ActiveRecord::Migration
  disable_ddl_transaction!

  def change
    add_index :users, :active, algorithm: :concurrently
  end
end

disable_ddl_transaction!CREATE INDEX CONCURRENTLYしたい場合は必須。すべてのマイグレーションはデフォルトでトランザクション下で実行されるようになっているので、それを無効にするためのもの。 またこれは指定したファイルでのみ適用され、他のマイグレーションは各自のトランザクションで実行される。

そして PostgreSQLCREATE INDEX CONCURRENTLYに該当するのが algorithm: :concurrentlyの部分。これを指定しておくことで今回期待するインデックス処理が実行されるようになる。

まとめ

  • Rails ではマイグレーションdisable_ddl_transaction!algorithm: :concurrentlyを指定するだけで容易に PostgreSQLCREATE INDEX CONCURRENTLYを実行することができる
  • ダウンタイムを避けることができる代わりに通常よりも処理に時間がかかる、負荷が上がるなどのデメリットもあると思うのでメリット、デメリットをちゃんと考慮して使ったほうが良いかも

参照