2012-04-05 17 views
36

¿Hay alguna manera de INSERTAR múltiples registros en lugar de uno a la vez?INSERTAR múltiples registros utilizando Ruby on Rails registro activo

tengo una tarea muy muy feo rastrillo que está haciendo lo siguiente ...

 VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2000-03-07", :party => row[45], :participate => participated(row[45])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2000-11-07", :party => row[46], :participate => participated(row[46])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "SP", :election => "2000-05-08", :party => row[47], :participate => participated(row[47])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2001-11-06", :party => row[48], :participate => participated(row[48])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2002-05-07", :party => row[49], :participate => participated(row[49])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2002-11-05", :party => row[50], :participate => participated(row[50])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "SP", :election => "2003-05-06", :party => row[51], :participate => participated(row[51])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2003-11-04", :party => row[52], :participate => participated(row[52])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2004-03-02", :party => row[53], :participate => participated(row[53])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2004-11-02", :party => row[54], :participate => participated(row[54])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "SP", :election => "2005-02-08", :party => row[55], :participate => participated(row[55])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2005-05-03", :party => row[56], :participate => participated(row[56])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2005-09-13", :party => row[57], :participate => participated(row[56])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2005-11-08", :party => row[58], :participate => participated(row[58])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "SP", :election => "2006-02-07", :party => row[59], :participate => participated(row[59])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2006-05-02", :party => row[60], :participate => participated(row[60])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2006-11-07", :party => row[61], :participate => participated(row[61])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2007-05-08", :party => row[62], :participate => participated(row[62])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2007-09-11", :party => row[63], :participate => participated(row[63])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2007-11-06", :party => row[64], :participate => participated(row[64])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2007-11-06", :party => row[65], :participate => participated(row[65])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2007-12-11", :party => row[66], :participate => participated(row[66])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2008-03-04", :party => row[67], :participate => participated(row[67])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2008-10-14", :party => row[68], :participate => participated(row[68])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2008-11-04", :party => row[69], :participate => participated(row[69])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2008-11-18", :party => row[70], :participate => participated(row[70])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2009-05-05", :party => row[71], :participate => participated(row[71])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2009-09-08", :party => row[72], :participate => participated(row[72])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2009-09-15", :party => row[73], :participate => participated(row[73])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2009-09-29", :party => row[74], :participate => participated(row[74])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2009-11-03", :party => row[75], :participate => participated(row[75])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2010-05-04", :party => row[76], :participate => participated(row[76])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2010-07-13", :party => row[77], :participate => participated(row[77])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2010-09-07", :party => row[78], :participate => participated(row[78])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2010-11-02", :party => row[79], :participate => participated(row[79])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2011-05-03", :party => row[80], :participate => participated(row[80])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2011-09-13", :party => row[81], :participate => participated(row[81])) 
     VoteRecord.create(:prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2011-11-08", :party => row[82], :participate => participated(row[82])) 

Esto tiene que ser extremadamente ineficiente y tiene que haber una mejor manera ...

+2

"Esto tiene que ser extremadamente ineficiente", ¿qué te hace pensar eso? –

+1

es feo. jaja. Si hay una mejor manera de que pueda comparar a los dos y volver con usted? –

Respuesta

57

El método create también toma una matriz como parámetro.

VoteRecord.create(
    [ 
    { :prospect_id => prospect.id, :state => "OH", :election_type => "GE", :election => "2011-11-08", :party => row[82], :participate => participated(row[82]) }, 
    { :prospect_id => prospect.id, :state => "OH", :election_type => "PR", :election => "2011-09-13", :party => row[81], :participate => participated(row[81]) } 
    ... 
    ] 
) 

Sin embargo, esto todavía ejecuta una consulta SQL por entrada en lugar de una sola consulta SQL. Es más eficiente, porque solo tiene que crear un solo objeto activerecord bajo el capó.

Si va a insertar tantas filas desde el mismo cliente al mismo tiempo, uso de las instrucciones INSERT con múltiples enumera los valores para insertar varias filas a la vez. Esto es considerablemente más rápido (muchas veces más rápido en algunos casos de ) que el uso de instrucciones INSERT separadas de una sola fila. Si está agregando datos a una tabla no vacía, puede ajustar la variable bulk_insert_buffer_size para hacer la inserción de datos aún más rápido. Consulte la Sección 5.1.3, "Variables del sistema del servidor".

From the mysql page (pero supongo que debe ser el mismo para otros DBS)

+20

esto no hace una sola declaración SQL, hace una por objeto nuevo. Estoy probando esto en Rails 3.2. ¿Tal vez fue diferente en versiones anteriores? –

+0

@JohnBachir No estoy seguro acerca de las diversas versiones, pero si desea asegurarse de que se hace de una vez (para el rendimiento), puede utilizar una transacción. Aunque tal vez los rieles ya lo están haciendo? ... –

+2

@Nolan, una transacción no lo hará en una sola declaración. a eso me refiero - haciendo todas las inserciones con una declaración SQL. –

14

Por desgracia, no es posible en los carriles de la caja.

Sin embargo, activerecord-import es una gran joya para Rails 3.x que agrega un método import a sus clases de modelo, y hace exactamente lo que usted desea como una sola instrucción de inserción de SQL.

+0

funciona maravillosamente con mi configuración Rails 4 Postgres 9.3 Ruby 2.1 y es infinitamente más rápida que mi método anterior de invocar crear en cada iteración o el método de llamada de Klump crear una vez en una matriz. –

+1

este artículo me fue muy útil https: //www.coffeepowered.net/2009/01/23/mass-inserteding-data-in-rails-without-killing-your-performance/ – allenwlee

-4

se puede envolver sus estados de ActiveRecord dentro de un ActiveRecord::Base.transaction:

ActiveRecord::Base.transaction do 
    1000.times { Post.create(options) } 
end 

Ver this post para otras técnicas.

+0

El OP preguntó si podían hacer algo mejor que insertar uno a la vez. Una transacción no impide eso aunque ayuda un poco. [Este punto de referencia] (https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/) por ejemplo, encuentra que, al realizar una transacción, mejorar en un 30% un solo 'INSERT' fue 7000% más rápido. Me gustaría ir con lo que dijo @nonrectangular. – Adamantish

+0

No lo use, ya que no se comprometerá con la base de datos hasta que se inserten los 1000 registros. Esto es como posponer los problemas. – Antony