Rails seedファイルに大量のデータを早くいれる方法

Seedファイルにコードを書いて一度にたくさんのデータを入れたい時ってありませんか？
自分は素数の数をデータベースにたくさん入れたく、スピード早くいれる方法を考えた。


環境: ruby2.1
     rails4.0.2
パソコンのスペック：
　　MacBookAir 13-inch, Mid 2011
　　プロセッサ  1.7 GHz Intel Core i5
　　メモリ  4 GB 1333 MHz DDR3

データベース: mysql2

テーブルは非常にシンプルなもの
下記マイグレーション
カラムは二つのみ
IDとprime_numberの二つ


```rb

class CreatePrimeNumbers < ActiveRecord::Migration
  def change
    create_table :prime_numbers do |t|
      t.integer :prime_number
    end
  end
end

```

コマンドは下記を何度も試して計測する。

```
> bundle exec time spring rake db:reset
```

極力メモリは消費しないようにする。ブラウザーも閉じて、必要ないアプリケーションも閉じる。
起動しているアプリはターミナルとエディタぐらいにする。

[ネットで■ パフォーマンス比較 Cassandra、Mongodb、SQLite、H2、MySQL、Postgres ](http://d.hatena.ne.jp/cypher256/20121013/p1)の記事をみて最初はSQLite3を使おうと思った。

seedファイルは下記の通り

```rb:seed.rb
require 'Prime'
Prime.each(10 ** 6) do |prime|
  PrimeNumber.create(
  prime_number: prime
)
end
```

0から１００万までの間に素数が何個あるか検査してデータベースに入れていく。

```
> bundle exec time spring rake db:reset
-- create_table("prime_numbers", {:force=>true})
   -> 0.0120s
-- initialize_schema_migrations_table()
   -> 0.0057s
      172.77 real         0.34 user         0.04 sys

```

##172秒(sqlite3)だった。

mysqlで試してみた。

```
> bundle exec time spring rake db:reset
-- create_table("prime_numbers", {:force=>true})
   -> 0.0279s
-- initialize_schema_migrations_table()
   -> 0.0396s
       97.99 real         0.34 user    
```

##97秒(mysql2)と1.7倍に縮む、、、、

ActiveRecordを使ってるから遅い。
だからSQLの直打ちで書いて試してみる。

```rb:seed.rb
require 'Prime'

Prime.each_with_index(10 ** 6) do |prime, index|
  ActiveRecord::Base.connection.execute("Insert INTO prime_numbers (id, prime_number) VALUES
  (  #{index + 1}, #{prime} );")
end
```

```
> bundle exec time spring rake db:reset
-- create_table("prime_numbers", {:force=>true})
   -> 0.0173s
-- initialize_schema_migrations_table()
   -> 0.0368s
       32.03 real         0.33 user         0.03 sys
```

##結果は32秒(mysql2)と大幅にアップ！

ちなみにSQLite3だと88秒(sqlite3)これまた大幅にアップ。

並列処理したらもっと早くなるんじゃないかと思い試してみる。
Rubyで並列処理が簡単に導入できるgemのParallelを入れる。

```rb:seed.rb
require 'Prime'
require 'parallel'

primes = Prime.each_with_index(10 ** 6)

Parallel.each(primes, :in_processes => 10 ) do |prime, index|
  ActiveRecord::Base.connection.execute("Insert INTO prime_numbers (id, prime_number) VALUES
      (  #{index + 1}, #{prime} );")
end
```

```
> bundle exec time spring rake db:reset
-- create_table("prime_numbers", {:force=>true})
   -> 0.0241s
-- initialize_schema_migrations_table()
   -> 0.0410s
       13.96 real         0.33 user         0.03 sys
```

##結果は13秒!!!
19秒も縮んだ。

当初の172秒から13秒までと約13倍も早くなった。

バルクインサートしたら早くなるんじゃないか？？と言うコメントをいただいて試してみた。
参考記事(http://qiita.com/xend/items/79184ded56158ea1b97a)
activerecord-importをgemにインストールすればimportのメソッドで使えるようになるらしい。

```rb:seed.rb
require 'Prime'
arr_prime = []
Prime.each(10 ** 6) do |prime|
  arr_prime << PrimeNumber.new(:prime_number => prime)
end

PrimeNumber.import arr_prime
```

```
 bundle exec time spring rake db:reset
-- create_table("prime_numbers", {:force=>true})
   -> 0.0439s
-- initialize_schema_migrations_table()
   -> 0.0468s
       12.80 real         0.40 user         0.04 sys
```

##結果は12秒！！！

SQLで直書きで書けばもっと早くなりそうだがあまりうまくいかず、思案中である。

まだまだもっと早くする方法があるのか探し中。

もっと早くする方法があればコメントお待ちしております！