2011-07-28 24 views
7

estoy experimentando a lo grande y calculando desafíos de energía al hacer la migración de datos grande (varios 100.000 filas). Estoy desarrollando un servicio que maneja una gran cantidad de datos en rieles. Nuestros modelos cambian constantemente a medida que nos volvemos cada vez más exigentes con nuestro diseño. Esto genera muchas migraciones en nuestra base de datos, que es una base de datos Postgres 9.0. A menudo, estas migraciones también incluyen algún tipo de migración en los datos en sí. Ayer descubrimos que necesitábamos mover un atributo 'texto' en un modelo a un modelo separado para que el atributo ya no fuera solo un atributo en el modelo sino una relación de uno a muchos.enormes migraciones de datos en los carriles

Mi migración parecía algo como esto:

def self.up 
    create_table :car_descriptions do |t| 
    t.integer :car_id 
    t.text :description 

    t.timestamps 
    end 

    Car.find_each do |car| 
    if car.description.present? 
     car.descriptions.build :description => car.description 
    end 
    car.save 
    end 
    remove_column :cars, :description 
end 

Ahora el problema es, que esto está funcionando muy lento, y aún peor, si me puse un contador, e imprime el progreso, puedo ver que la migración se está ejecutando más lento y más lento con el tiempo. En mi monitor de actividad puedo ver que el proceso de ruby ​​está ocupando más y más memoria.

Así que mi pregunta es - ¿existe una mejor manera de hacer grandes migraciones de datos de este tipo?

Respuesta

12

No debe usar ActiveRecord aquí para migrar los datos de su modelo Car al modelo CarDescription. En su lugar, debe replicar ejecutar sql en bruto (ejecutar desde la migración). En mi último trabajo, tuvimos tantos problemas con enormes datos, y la ejecución de archivos raw en bruto dio como resultado migraciones mucho más rápidas (aunque a veces todavía tardaban de 5 a 6 horas). Otra práctica que desarrollamos con el tiempo después de muchas experiencias amargas fue que siempre copiamos nuestra base de datos de producción a nuestro servidor de ensayo y ejecutamos la migración al menos dos veces en la puesta en escena. Siempre se nos ocurrió algún proceso (específico para la migración) que fue un gran ahorro de tiempo después de esta práctica. En ocasiones, el proceso incluía la caída manual de algunos índices, la ejecución de la migración y la creación manual de esos índices nuevamente.

En el caso actual, el SQL puede ser algo como esto:

INSERT INTO car_descriptions(car_id, description) SELECT id, description FROM cars 

espero que les sea útil, que me haga saber si puedo añadir algo a la respuesta.

+0

Dale un golpe. Esto debería ahorrarle una tonelada de memoria. – erik

+0

Gran respuesta. Nosotros también probamos eso, y parece que es un enfoque mucho mejor. Gracias por los pequeños consejos sobre sus propias experiencias :-) Encontré [este enlace] (http://railsapi.com/doc/rails-v3.0.8rc1/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#M004596) sosteniendo algunos información sobre métodos que ayuda a limpiar cosas solo un poco en nuestro código de rieles, al hacer declaraciones SQL manuales. –

+0

@Niels Usar los métodos era lo que quise decir con "ejecutar desde la migración" :). Agregar el enlace allí hubiera sido mejor. – rubish

Cuestiones relacionadas