· 2 min read

ALTER TABLE mit Rails 3 und MySQL

Der erwähnte Commit ist im GitHub einsehbar (https://github.com/rails/rails/commit/30176f28a41681c7607eed39d03501327869d40c).

Das Problem, das bisher bei Änderungen an Tabellen bestand, war die Art wie MySQL diese ausführt. Wenn man von folgendem Beispiel ausgeht: Es sollen zwei Spalten hinzugefügt werden und der Datentyp einer weiteren soll geändert werden.

[ruby] change_table(:users) do |t| t.string :im_handle t.belongs_to :company t.change :birthdate, :datetime end [/ruby]

Diese Migration führte bisher zu drei separat ausgeführten Befehlen:

[bash] ALTER TABLE `users` ADD `im_handle` varchar(255) ALTER TABLE `users` ADD `company_id` int(11) ALTER TABLE `users` CHANGE `updated_at` `updated_at` datetime DEFAULT NULL [/bash]

Diese Aktion ist bei kleinen Datenbanken “relativ” unproblematisch, aber führt zu Problemen bei größeren.Denn wenn man einen Blick in die MySQL Dokumentation wirft, wird man feststellen, dass MySQL einiges im Hintergrund ausführt, um die Änderung durchzuführen. Die grobe Reihenfolge sieht ungefähr so aus:

  1. Die Tabelle wird gesperrt (lock). Kein UPDATE und INSERT mehr zugelassen
  2. Eine temporäre Kopie der Tabelle samt Inhalt wird angelegt
  3. Die gewünschten Änderungen werden auf die Kopie angewendet
  4. Die originale Tabelle wird durch die geänderte Kopie ersetzt

Wenn nun das oben gezeigte Beispiel ausgeführt wird, würden diese Schritte drei mal ausgeführt werden. Das ist nicht unbedingt performant und nicht immer gewünscht.

In den kommenden Rails-Versionen kann dieser Vorgang als Bulk durchgeführt werden. Dadurch werden alle Änderungen als einziger Befehl durchgeführt:

[ruby] change_table(:users, :bulk => true) do |t| t.string :im_handle t.belongs_to :company t.change :birthdate, :datetime end [/ruby]

Durch den zusätzlichen Parameter “bulk => true” werden die einzelnen Statements zu einer zusammengefasst:

[bash] ALTER TABLE `users` ADD COLUMN `im_handle` varchar(255), ADD COLUMN `company_id` int(11), CHANGE `updated_at` `updated_at` datetime DEFAULT NULL [/bash]

Dadurch werden Datenbankänderungen in Zukunft nicht nur schneller sondern auch atomarer.

Back to Blog