はじめに
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`