はじめに
Railsマイグレーションでbulk: true
を使って複数のカラムを追加した際のSQLログを比較し、挙動の違いを備忘録としてまとめます。検証環境はMySQLを前提としています。
結論
-
change
メソッドでbulk: true
を指定しても、ロールバック時にはbulk: true
が効かず、カラムごとに個別のALTER TABLE
が発行される - マイグレーションとロールバックの両方で
bulk: true
を効かせ、処理をアトミックに実行したい場合は、up
/down
メソッドに分けて両方にbulk: true
を指定する
前提知識
DDL(Data Definition Language)
CREATE TABLE
/ ALTER TABLE
/DROP TABLE
など、スキーマ構造を変更するSQL
MySQLにおけるDDLの特徴
- 実行時に暗黙的にコミットされる
- 一つのDDL文はアトミックに実行される(全て成功するか、全て失敗するか)
bulk
オプション
- テーブル定義変更時に、複数の変更を1つの
ALTER TABLE
にまとめるオプション - デフォルト値は
false
実装例
1. change
メソッドの場合
結果: bulk: true
はマイグレーション実行時のみ有効
class AddColumnsOnSampleItems < ActiveRecord::Migration[6.1]
def change
change_table :sample_items, bulk: true do |t|
t.integer :status_code
t.string :category_label
end
end
end
マイグレーション実行時
$ rails db:migrate
== 20250904070555 AddColumnsOnSampleItems: migrating ==========================
-- change_table(:sample_items, {:bulk=>true})
-> 0.0755s
== 20250904070555 AddColumnsOnSampleItems: migrated (0.0757s) =================
(71.5ms) ALTER TABLE `sample_items` ADD `status_code` int, ADD `category_label` varchar(255)
ロールバック実行時
$ rails db:rollback
== 20250904070555 AddColumnsOnSampleItems: reverting ==========================
-- remove_column(:sample_items, :category_label, :string)
-> 0.0968s
-- remove_column(:sample_items, :status_code, :integer)
-> 0.1003s
== 20250904070555 AddColumnsOnSampleItems: reverted (0.2016s) =================
(90.1ms) ALTER TABLE `sample_items` DROP COLUMN `category_label`
(93.7ms) ALTER TABLE `sample_items` DROP COLUMN `status_code`
2. up
/down
メソッド
結果: bulk: true
をマイグレーションとロールバックの両方に適用可能
class AddColumnsOnSampleItems < ActiveRecord::Migration[6.1]
def up
change_table :sample_items, bulk: true do |t|
t.integer :status_code
t.string :category_label
end
end
def down
change_table :sample_items, bulk: true do |t|
t.remove :status_code
t.remove :category_label
end
end
end
マイグレーション実行時
$ rails db:migrate
== 20250904070555 AddColumnsOnSampleItems: migrating ==========================
-- change_table(:sample_items, {:bulk=>true})
-> 0.0538s
== 20250904070555 AddColumnsOnSampleItems: migrated (0.0540s) =================
(49.1ms) ALTER TABLE `sample_items` ADD `status_code` int, ADD `category_label` varchar(255)
ロールバック実行時
$ rails db:rollback
== 20250904070555 AddColumnsOnSampleItems: reverting ==========================
-- change_table(:sample_items, {:bulk=>true})
-> 0.1045s
== 20250904070555 AddColumnsOnSampleItems: reverted (0.1092s) =================
(92.4ms) ALTER TABLE `sample_items` DROP COLUMN `status_code`, DROP COLUMN `category_label`