2011-05-07 5 views
10

lo que necesito:¿ActiveRecord realiza inserciones/eliminaciones a granel cuando está dentro de una transacción?

  1. asegurar actualizaciones atómicas (sin registro puede se procesa 2 veces)
  2. eliminación masiva para todas las 1000 filas seleccionado

@queue = Queue.where("col = 1").limit(1000) 
ids = [] 
@queue.each do |row| 
    Queue.do_something(row) 
    ids << row.id 
end 

Queue.delete_all("id in (#{ids.join(',')}) ") 

es el mismo que

Queue.transaction do 
    @queue.each do |row| 
     Queue.do_something(row) 
     Queue.delete(row.id) 
    end 
end 

Respuesta

15

Para insertos:

ActiveRecord no realiza una inserción masiva cuando se utiliza una transacción. Sin embargo, acelera un poco las cosas ya que utiliza una sola transacción para ejecutar todas las instrucciones INSERT en lugar de una transacción por instrucción INSERT de lo contrario.

Así:

Queue.transaction do 
    @queue.each do |row| 
    # an INSERT is done here 
    end 
end 

va a ser más rápido que:

@queue.each do |row| 
    # an INSERT is done here 
end 

Para obtener más información sobre cómo hacer realmente inserciones masivas, echa un vistazo a este article.

Para eliminaciones:

El ActiveRecord delete_all llamada es comunicado de una sola SQL DELETE, así que supongo que usted podría considerar esto como una mayor borrar (sin necesidad de utilizar una transacción aquí, ya que ya está encapsulada en una transacción por ActiveRecord) Este no es el caso cuando se llama al delete en cada registro, lo que dará como resultado varias sentencias SQL DELETE, por lo tanto, múltiples transacciones iniciadas y comprometidas y un rendimiento global más lento.

+0

En mi caso tengo que borrar registros garantizando al mismo tiempo no hay otros procesos/instancias procesarán el mismo registro. Utilicé la cláusula de SQL de "FOR UPDATE" de mysql para bloquear los registros seleccionados y usar la transacción de ActiveRecord porque pensé que ActiveRecord realizaría esas eliminaciones como una sola masa eliminar sql o hacerlo más rápido. – newx

+0

El problema es que tuve el mismo correo electrónico (expediente de COLA) entregó 2 veces – newx

+0

realmente se pone mucho más rápido cuando se utiliza la solución ... Gracias! :-) –

3

le sugiero que tome un vistazo a ActiveRecord importación: https://github.com/zdennis/activerecord-import.

estoy usando esta herramienta para insertar entre 10.000 y 100.000 filas de datos.

books = [] 
10.times do |i| 
    books << Book.new(:name => "book #{i}") 
end 
Book.import books 

Si estás usando MySQL, sino que también apoya EN DUPLICADO KEY UPDATE para que pueda insertar de forma inteligente nueva/actualizar filas antiguas. https://github.com/zdennis/activerecord-import/wiki/MySQL:-On-Duplicate-Key-Update-Support

Cuestiones relacionadas