Rails, как перенести большой объем данных?
У меня есть приложение rails 3, работающее на более старой версии spree (корзина с открытым исходным кодом). Я сейчас обновляю его до последней версии. Это требует, чтобы я запускал многочисленные миграции в базе данных для совместимости с последней версией. Однако текущая база данных приложений примерно составляет около 300 МБ и для запуска миграции на моем локальном компьютере (mac os x 10.7, 4gb ram, 2.4GHz Core 2 Duo) требуется более 3 дней.
Я смог уменьшить это время до 16 часов, используя экземпляр ecazon ec2 (экземпляры On-Demand High-I/O, Quadruple Extra Large). Но еще 16 часов все еще долго, так как мне придется снять сайт, чтобы выполнить это обновление.
Есть ли у кого-нибудь другие предложения, чтобы снизить это время? Или какие-либо советы по увеличению производительности миграции?
FYI: использование ruby 1.9.2 и ubuntu на экземпляре amazon.
Ответы
Ответ 1
-
Отбрасывание индексов заранее и добавление их снова после этого - хорошая идея.
-
Также заменяем .where(...). Каждый с .find_each и, возможно, добавление транзакций может помочь, как уже упоминалось.
-
Замените .save! с .save(: validate = > false), потому что во время миграции вы не получаете случайных входов от пользователей, вы должны делать хорошо известные обновления, а валидации составляют большую часть времени выполнения. Или использование .update_attribute также пропустит проверки, в которых вы обновляете только одно поле.
-
По возможности используйте меньшее количество объектов AR в цикле. Создание и последующий сбор мусора требует процессорного времени и использует больше памяти.
Ответ 2
Возможно, вы уже это подумали:
-
Скажите db не беспокоиться о том, чтобы все было на диске (без WAL, no fsync и т.д.), теперь у вас есть память db, которая должна иметь очень большое значение. (Поскольку вы взяли db offline, вы можете просто восстановить из резервной копии в маловероятном случае потери мощности или аналогичного). Включите fsync/WAL, когда вы закончите.
-
Скорее всего, вы сможете выполнить некоторые миграции, прежде чем использовать db в автономном режиме. Протестируйте это, конечно. Эта большая миграция пользователей вполне может быть реализована вживую. Убедитесь, что вы не делаете этого в транзакции, вам может потребоваться немного изменить их.
Я не знаком с вашей конкретной ситуацией, но я уверен, что есть еще больше вещей, которые вы можете сделать, если этого недостаточно.
Ответ 3
Этот ответ больше касается подхода, чем конкретного технического решения. Если ваши основные критерии - минимальное время простоя (и целостность данных, конечно), то лучшей стратегией для этого является использование рельсов!
Вместо этого вы можете выполнить всю тяжелую работу и оставить только критическую миграцию данных в реальном времени (я использую "миграцию" в смысле не-рельсов здесь) в качестве шага во время переключения.
Итак, у вас есть текущее приложение с его схемой db и производственными данными. Вы также (предположительно) имеете версию разработки приложения, основанную на обновленных драгоценных камнях с новой схемой db, но без данных. Все, что вам нужно сделать, это выяснить способ преобразования данных между ними. Это можно сделать несколькими способами, например, используя чистые SQL и временные таблицы, где это необходимо, или с использованием SQL и ruby для создания операторов вставки. Эти шаги можно разделить так, чтобы данные, которые являются довольно "статическими" (справочные таблицы, продукты и т.д.), Могут быть загружены в db раньше времени, а данные, которые изменяются чаще (пользователи, сообщения, заказы и т.д.), Могут быть выполненных на этапе миграции.
Вы должны script выполнить эту процедуру экспорта-преобразования-импорта, чтобы она была повторяемой и провела тесты/проверки после ее завершения, чтобы обеспечить целостность данных. Если вы можете организовать доступ к новой производственной базе данных во время переключения, тогда вам будет легко запустить script против нее. Если вы ограничены процессом выпуска (например, webistrano), вам может потребоваться перевести его в рельсовую миграцию, но вы можете запустить raw SQL с помощью execute.
Ответ 4
Взгляните на этот драгоценный камень.
https://github.com/zdennis/activerecord-import/
data = []
data << Order.new(:order_info => 'test order')
Order.import data
Ответ 5
Несчастливо, только что разобщенное решение. То, что на самом деле медленнее в рельсах, - это модели activerecord. Они не подходят для таких задач.
Если вам нужна быстрая миграция, вам придется сделать это в sql.
Существует другой подход. Но вам придется переписывать большую часть миграций...