Утечка памяти в Rails 3.0.11 миграции - PullRequest
0 голосов
/ 16 марта 2012

Миграция содержит следующее:

Service.find_by_sql("select 
                       service_id, 
                       registrations.regulator_given_id, 
                       registrations.regulator_id
                     from
                       registrations
                     order by
                       service_id, updated_at desc").each do |s|
  this_service_id = s["service_id"]
  if this_service_id != last_service_id
    Service.find(this_service_id).update_attributes!(:regulator_id => s["regulator_id"],                    
                   :regulator_given_id => s["regulator_given_id"])
    last_service_id = this_service_id
  end
end

и он потребляет память до такой степени, что он не будет работать на 512 МБ, разрешенных в Heroku (таблица регистрации содержит 60 000 элементов). Есть известная проблема? Обходной путь? Исправить в более поздней версии Rails?

Заранее спасибо

Изменить следующий запрос для уточнения:
Это все релевантный источник - остальная часть миграции создает два новых столбца, которые заполняются. Ситуация такова, что у меня есть данные об услугах из нескольких источников (регуляторы услуг) в таблице регистрации. Я решил «продвинуть» некоторые данные ([prime] regulator_id и [prime] regulator_given_key) в таблицу услуг для основных регуляторов, чтобы ускорить определенные запросы.

Ответы [ 2 ]

0 голосов
/ 16 марта 2012

(Примечание: OP сообщает, что это не сработало)

Попробуйте что-то вроде этого:

previous = nil
Registration.select('service_id, regulator_id, regulator_given_id')
    .order('service_id, updated_at DESC')
    .each do |r|
  if previous != r.service_id
    service = Service.find r.service_id
    service.update_attributes(:regulator_id => r.regulator_id, :regulator_given_id => r.regulator_given_id)
    previous = r.service_id
  end
end

Это своего рода хакерский способ получения самой последней записи из regulators - несомненно, есть лучший способ сделать это с DISTINCT или GROUP BY в SQL, все в одном запросе, который не только быть намного быстрее, но и более элегантным. Но это просто миграция, верно? И я не обещал элегантного. Я также не уверен, что это сработает и решит проблему, но я думаю так: -)

Ключевое изменение заключается в том, что вместо использования SQL используется AREL, что означает (я думаю), что операция обновления выполняется один раз для каждой связанной записи , когда AREL возвращает их . С SQL вы возвращаете их все и сохраняете в массиве, а затем обновляете их все. Я также не считаю необходимым использовать предложение .select(...).

Очень заинтересован в результате, поэтому дайте мне знать, если он работает!

0 голосов
/ 16 марта 2012

Это загрузит все 60000 предметов за один раз и сохранит вокруг себя эти 60000 объектов AR, которые будут занимать достаточное количество памяти.Rails предоставляет метод find_each для разбиения такого запроса на куски по 1000 объектов за раз, но он не позволяет вам указывать порядок, как вы.

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

Альтернативой является добавление условий к вашему запросу, которые гарантируют, что вы не вернете уже обработанные элементы, например, указав, что service_id будет меньше, чем ранее возвращенные значения.Это сложнее, если при сравнении в этом вопросе некоторые элементы равны.При использовании обеих этих схем типа подкачки вам, вероятно, нужно подумать о том, что произойдет, если строка будет вставлена ​​в вашу таблицу регистрации во время ее обработки (вероятно, это не проблема для миграций, если вы запускаете их с отключенным доступом к сайту)

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