最近、PostgreSQL を使用している Rails プロジェクトでCREATE INDEX CONCURRENTLY
する機会があったのでメモ。
CREATE INDEX CONCURRENTLY とは
通常のインデックス作成処理では、処理が完了するまで対象テーブルへの書き込みはロックされる(読み取りはロックされない)。
そしてテーブルのレコードが大量にある場合、インデックス作成に数時間かかることも考えられるので、その間ずっと書き込みがロックされるのはツラい。
PostgreSQL は CREATE INDEX
でCONCURRENTLY
というオプションをサポートしており、書き込みのロックを行わずにインデックスを作成することが可能。
ただし、これはサービスのダウンタイムが回避できる代わりに、通常よりも処理に時間がかかり、負荷も上がることが考えられる。
またここでは 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
したい場合は必須。すべてのマイグレーションはデフォルトでトランザクション下で実行されるようになっているので、それを無効にするためのもの。
またこれは指定したファイルでのみ適用され、他のマイグレーションは各自のトランザクションで実行される。
そして PostgreSQL のCREATE INDEX CONCURRENTLY
に該当するのが algorithm: :concurrently
の部分。これを指定しておくことで今回期待するインデックス処理が実行されるようになる。
まとめ
- Rails ではマイグレーションで
disable_ddl_transaction!
とalgorithm: :concurrently
を指定するだけで容易に PostgreSQL のCREATE INDEX CONCURRENTLY
を実行することができる - ダウンタイムを避けることができる代わりに通常よりも処理に時間がかかる、負荷が上がるなどのデメリットもあると思うのでメリット、デメリットをちゃんと考慮して使ったほうが良いかも