Почему приложение умирает во время миграции рельсов? - PullRequest
0 голосов
/ 02 февраля 2012

Мне обычно нужно выполнять миграции следующим образом:

class AddNewFieldToMember < ActiveRecord::Migration
  def self.up
    add_column :members, :new_field, :string, :default => 'instant'

    # Set existing records
    Member.reset_column_information
    Member.all.each do |member|
      member.new_field = 'instant'
      member.save
    end

  end

  def self.down
    remove_column :members, :new_field
  end
end

Эта конкретная таблица участников содержит около 10 000 записей.Когда мы запускаем такие миграции, все умирает.Миграция занимает не менее 5 минут.Rails не отвечает, postgresql также не отвечает.

Почему это так?Что можно сделать, чтобы избежать простоев миграции?Есть ли лучший способ добавить миграции и обновить существующие записи?

Спасибо

Ответы [ 4 ]

1 голос
/ 02 февраля 2012

@ MartinSamson прав, по умолчанию должен справиться с этой ситуацией.И если по какой-то причине вам нужно было выполнить какое-то другое обновление значений, которые по умолчанию не могут быть обработаны, то это гораздо эффективнее сделать в SQL.Например,

execute("update members set new_field='value'")

вместо того, чтобы выполнять все сущности таким образом.

О, и еще, я настоятельно рекомендую НИКОГДА не ссылаться на ваши объекты в ваших миграциях, это просто приводит к проблемам.Например, что если позже вы удалите класс Member из своего приложения.Тогда ваши миграции потерпят неудачу в следующий раз, когда вы запустите их с нуля, что раздражает.Гораздо лучше просто сделать это в SQL.

1 голос
/ 02 февраля 2012

Если вы добавляете новый столбец со значением по умолчанию, вам не нужно зацикливать существующие записи, чтобы добавить его.Об этом должен позаботиться механизм базы данных.

PostgreSQL может зависать, если миграция происходит внутри транзакции, а изменяемые данные также изменяются где-то еще во время транзакции.

0 голосов
/ 02 февраля 2012

Вам следует избегать доступа к моделям внутри ваших миграций, если это действительно не неизбежно.

Ваш конкретный случай может быть решен с помощью:

class AddNewFieldToMember < ActiveRecord::Migration
  def self.up
    add_column :members, :new_field, :string, :default => 'instant'

    # Set existing records
    execute <<-SQL
      update members set new_field = 'instant';
    SQL
  end

Если каким-либо образом вам действительно нужно использовать вашу модель внутри миграции, используйте хотя бы самый эффективный метод find_each вместо all.each. Оборачивая цикл внутри транзакции, вы также можете получить лучшие результаты.

0 голосов
/ 02 февраля 2012

Мартин прав, что вам, возможно, даже не нужно это делать, но если вы хотите установить значение явно или вам нужно сделать это иначе ...

Если у вас есть 10000 членов, тогда вывыдача 10 000 операторов обновления с неявными транзакциями.

Выезд update_all

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...