2011年4月3日日曜日

PythonでMongoDBに大量のデータをinsertしてみた(その2)

以前MongoDBに大量データをinsertしてみましたが、まとめてinsertした場合、どの程度効果があるのか確認してみました。MongoDBは最新版のv1.8.0です。

まず、MongoDBを起動します。

./mongod --dbpath datapath --logpath logpath --fork

PyMongoというPython用ドライバをinstallする際に以下のようなエラーになりましたが、一応インストール自体は終わったので問題無かな・・と思います。
**************************************************************
WARNING: The pymongo._cmessage extension module could not
be compiled. No C extensions are essential for PyMongo to run,
although they do result in significant speed improvements.

Above is the ouput showing how the compilation failed.
**************************************************************

その後、以下のPythonコードを実行します。いつものように100万行のCSVファイルを1件ずつ読み込み、CSVに記載してある2列をそれぞれ、id列、value列として、hashコレクションにinsertしていきます。
-----------------------------------------------------------
#!/usr/bin/env python
import csv
import pymongo
import time

if __name__ == '__main__':
    start = time.time()
    L=[]
    cnt = 0
    c = pymongo.Connection()
    db = c.testdb
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
  D = {}
  D["id"] = row[0]
  D["value"] = row[1]
  L.append(D)
  cnt += 1
  if cnt % 1000 == 0:
   db.hash.insert(L)
   D={}
   L=[]
  print time.time()-start
-----------------------------------------------------------
実行時間は96sでした。

また、今回改めて1件ずつinsertするやり方も確認しました。
-----------------------------------------------------------
#!/usr/bin/env python
import csv
import pymongo
import time

if __name__ == '__main__':
    start = time.time()
    D = {}
    c = pymongo.Connection()
    db = c.testdb
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
  D["id"] = row[0]
  D["value"] = row[1]
  db.hash.insert(D)
  D={}
 print time.time()-start
-----------------------------------------------------------
実行時間は230sでした。

つまり、1000件ずつまとめてinsertする方が2倍以上高速に動作しているようです。

因みにですが、MongoDBv1.8からジャーナルモードをサポートしているようです。RDBのように、変更履歴を先にLogファイルとして書き出し、耐障害性の向上を目指しているようです。そうすると、パフォーマンスは落ちるのだろうなーと思って実験してみました。

ジャーナルモードをONとするには起動の際にオプションで指定します。
./mongod --dbpath datapath --logpath logpath --journal --fork

結果だけ言うと、パフォーマンスは1件ずつinsertした場合でも1000件まとめてinsertした場合でもジャーナルモードで無い場合とほとんど変化ありませんでした。どうもMongoDBでの実装ではinsert毎にDISKに書き出しているようでは無いようです。

---以下、manualの抜粋
MongoDB performs group commits (batch commits) when using the --journal option. This means that a series of operations over many milliseconds are committed all at once. This is done to achieve high performance.

つまり、、journalモードと言ってもinsertしたデータが必ず保護されるという訳では無くて、耐障害性がjournalモードで無い場合よりも、"ある程度"向上するだけ。という事かなと思いました。