2012-04-05 13 views
36

一度に1つではなく複数のレコードをINSERTする方法はありますか?ruby​​ on railsアクティブレコードを使用して複数のレコードを挿入する

私は次のことをやっている非常に非常に醜いrakeタスクを持っている...

 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])) 

これは非常に非効率的であることが、より良い方法がなければならないが...

+2

「これは非常に非効率的でなければなりません。 –

+1

その醜い。ハハ。より良い方法があれば、私は2つのベンチマークをして、あなたと戻ってくることができますか? –

答えて

57

create方法パラメータとして配列もとります。

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]) } 
    ... 
    ] 
) 

ただし、1つのSQLクエリではなく、エントリごとに1つのSQLクエリが実行されます。これは、ボンネットの下に単一のアクティブレコードオブジェクトを作成するだけで済むため、より効率的です。

あなたが同時に同じクライアントから多くの行を挿入する場合は、複数の値を持つ 使用のINSERT文は、一度に複数の 行を挿入するために示しています。これは、別々の単一行のINSERTステートメントを使用するよりもかなり高速です(いくつかは の場合は何倍も高速です)。 空でないテーブルにデータを追加する場合は、 bulk_insert_buffer_size変数を調整して、データの挿入をさらに高速化できます。 5.1.3項「サーバー・システム変数」を参照してください。

From the mysql page

+20

これは単一のSQL文を実行せず、新しいオブジェクトごとに1つのSQL文を実行します。私はこれをレールで試しています3.2 - それは以前のバージョンでは違っていたのでしょうか? –

+0

@JohnBachirさまざまなバージョンについてはわかりませんが、一度に(パフォーマンスのために)完了したことを確認したい場合は、トランザクションを使用できます。多分レールはすでにそれをしていますか? –

+2

@Nolanトランザクションは1つのステートメントで完了しません。それは私が言及していることです - すべての挿入を1つのSQL文で行います。 –

14

残念ながら、それは箱から出してレールにはできません(私はそれが他のDBSで同じである必要がありますね)。

しかし、activerecord-importは、モデルクラスにimportメソッドを追加するRails 3.xの素晴らしい宝であり、正確に1つのSQL挿入ステートメントとして実行します。

+0

は、私のRails 4 Postgres 9.3 Ruby 2.1セットアップでうまく動作し、各繰り返しまたはKlumpの呼び出し方法配列に1回作成します。 –

+1

この記事は非常に参考になりました。https://www.coffeepowerednet/2009/01/23 /あなたのパフォーマンスを殺すことなくデータを挿入する/ – allenwlee

-4

あなたはActiveRecord::Base.transactionの内側にあなたのActiveRecordステートメントをラップすることができます:

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

は、他の技術のためのthis postを参照してください。

+0

OPは、一度に1つずつ挿入するよりもうまくいくかどうかを尋ねました。それは少し助けても、トランザクションはそれを防止しません。 [このベンチマーク](https://www.coffeepowered.net/2009/01/23/mass-inserting-data-in-rails-without-killing-your-performance/)では、トランザクションを投入すると30%改善すると、単一のINSERTが7000%速くなりました。私は@nonrectangularが言ったことと一緒に行くだろう。 – Adamantish

+0

1000レコードがすべて挿入されるまでデータベースにコミットしないので、これを使わないでください。これは問題を延期するようなものです。 – Antony

関連する問題