2010年11月28日日曜日

PythonでSqlite3に大量のデータをInsertしてみた

次はPython2.xでSqlite3に対して大量のデータをinsertしてみました。
尚、Sqlite3は少なくとも最新のPython2.xでは内部に組み込まれている為、特に何かをインストールする必要はありません。

これもPythonのDocumentを参照して以下のようなコードを作成して実行しました。
#!/usr/bin/env python
import csv
import sqlite3
import time

if __name__ == '__main__':
    start = time.time()
   c = sqlite3.connect('./testdb')
    i = 0
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        id = row[0]
        value = row[1]
        t = (id,value,)
        c.execute('insert into hash (id,value) values(?,?)',t)
        i += 1
        if i % 100000 == 0:
            c.commit()
            print "commit! %d" % i
    c.commit()
    c.close()
    end = time.time()
    print end-start
前回同様、neta.csvというファイルを1件ずつ読み込み、testdbのhashテーブルに対してデータをinsertしてます。100万件のデータをinsertするのにかかった時間は27.1sでした。

・上記の例では10万件でcommit()するようにしましたが、30万件程度に1回のcommit()とした場合、若干パフォーマンスがあがりました。
・pythonのsqlite3モジュールはデフォルトではAutoCommitではないようで明示的にCommitしなければ、データが格納されません。因みに、Connectの際に以下のように変更する事でAutoCommitと出来るようです。
c = sqlite3.connect('./testdb',isolation_level=None)
やってみると、我慢出来ない位、遅くなります。

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

今回はPython2.xでMongoDBに大量のデータをinsertしてみました。

PythonでMongoDBにアクセスするには、PyMongoというモジュールを使用します。
http://api.mongodb.org/python/1.9%2B/index.html


掲載されているDocumentに従い、以下のようなコードを作成して実行しました。
尚、以前にも使用したCSV(neta.csv)をinsertネタに使っています。
#!/usr/bin/env python
import csv
import pymongo
import time

if __name__ == '__main__':
    start = time.time()
    c = pymongo.Connection()
    db = c.testdb
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        id = row[0]
        value = row[1]
        t = {"id":id , "value":value}
        db.hash.insert(t)
    end = time.time()
    print end-start
CSVを1件ずつ読み込み、1件ずつネタをhashコレクションにinsert()を実行します。MongoDBでは特にCommitの概念はありません。100万件のデータをinsertするのに要した時間は234.9sでした。

2010年11月10日水曜日

MongoDBのCSVロード機能をSqlite3、PostgreSQLと比較してみた

DBMSにはCSV等の外部ファイルを一括ローディングする機能があるものがあります。今回はMongoDB,Sqlite3,PostgreSQLのCSVローディング機能を実行して速度を比較してみました。

0.CSVネタの準備
郵便番号のCSVがあったのでこれを使おうと思いましたが、思うところあって約50MBのデータを自作しました。1フィールド目=番号、2フィールド目=番号のSha1値という非常に簡単なもので、100万行分作成しました。(Pythonで作成してます)
↓こんな感じ…
------------------------------------------------
1,356a192b7913b04c54574d18c28d46e6395428ab
2,da4b9237bacccdf19c0760cab7aec4a8359010b0
3,77de68daecd823babbb58edb1c8e14d7106e83bb

999999,1f5523a8f535289b3401b29958d01b2966ed61d2
1000000,b27585828a675f5acfef052dd1a8cf0c6c1ee4b0
------------------------------------------------

↓Pythonで作成する際は以下のような感じで・・・
---------------------------------------------------
import hashlib

i=0
while i < 1000000:
 i += 1
 print str(i)+","+hashlib.sha1(str(i)).hexdigest()
---------------------------------------------------


尚、以下の確認は家のローカルPC(Dell製)で行いましたが、

CPU→ Celeron(R) Dual-Core CPU  T3000  @ 1.80GHz
OS→ Fedora13
です。



1.MongoDB

MongoDBにはmongoimportコマンドというものがあり、CSVファイルを一括ローディング可能です。以下のような形で実行しました。今回はtimeコマンドで時間を測定しています。

[user@user ~]$ time mongoimport -d test -c hash --dbpath /home/user/mongodata/ -f id,value --type csv --file /tmp/neta.csv

testデータベースのhashコレクションにid,valueというカラムを持ったneta.csvを格納します。結果は以下です。
----------------------
real    0m40.137s
user    0m30.579s
sys     0m8.410s
----------------------
何度か行いましたが、大体同じような結果になりました。
尚、他のデータでもやってみましたが、mongoimportコマンドは数字のみの値については全てnumber型?と解釈するようで、前に0が埋まっている数字を文字列としてローディングしようとしても前0は全てカットされました。また"--type CSV"を指定しないと、大量のエラーが出力されます。

※MongoDBのバージョンはv1.6.2です。


2.Sqlite3

.import コマンドによりCSVネタのローディングが可能です。
まず、TABLEを作成しました。
sqlite> create table hash ( id INTEGER PRIMARY KEY , value TEXT );

その後、
以下のコマンドでローディングを行います。
[user@user ~]$ time sqlite3 testdb ".import '/tmp/neta.csv' hash"
testdbのhashテーブルに対してneta.csvをローディングしました。
結果は以下の通りです。
----------------------
real    0m8.961s
user    0m6.609s
sys     0m0.949s
----------------------

すこしはまったのですが、sqlite3はデフォルトのDelimiterは"|"らしいのでCSVネタを
1|356a192b7913b04c54574d18c28d46e6395428ab
のように作成しなおしました。

※Sqlite3のバージョンは3.6.22です


3.PostgreSQL

COPYコマンドによりCSVの一括ローディングが出来ます。

まず、以下でテーブルを作ります。
testdb=# create table hash ( id integer PRIMERY KEY , value TEXT ) ;

その後、
COPY hash FROM '/tmp/neta.csv' DELIMITER '|' ;
と記載したファイル(copy.txt)を作成し、以下を実行します。

-bash-4.1$ time psql testdb -f /tmp/copy.txt
testdbに対してcopy.txtに記載してあるCOPYコマンドを実行しました。
結果は以下の通りです。
----------------------
real    0m12.746s
user    0m0.001s
sys     0m0.003s
----------------------

※PostgreSQLのバージョンは9.0です。


まとめ
Realだけで比較すると以下になります。
Mongodb…0m40.137s
Sqlite3…0m8.961s
Postgresql…0m12.746s

パフォーマンスが一番良いと勝手に考えていたMongoDBは実は一番悪いという結果になりました。もちろんこれだけでその製品のパフォーマンスを語る事は出来ませんが、少なくともCSVのローディング機能についてはSqlite3やPostgreSQLに軍配があがりました。

と言うか、MongoDB遅すぎっ!

これがMongoDBの構造的な問題なのか、まだまだ改善の余地があるのかは不明です。また、上記確認ですが、全てインストール時のデフォルトの状態で実施しており、何らかのパラメータをいじってチューニング、、、みたいな事は一切していません。