以前、PythonのPostgreSQL用のドライバがうまくインストール出来ないと記載しましたが、python-develが入って無かっただけっぽいです。
yum install python-devel
で、
① ocpgdb1.0.3
② psycopg2-2.4
③ PyGreSQL-4.0
④ pg8000-1.08
の全てのドライバがinstall可能でした。
上記はPython2.6及び、2.7で確認しましたが、2.7の場合は④のインストールがいじらないとうまくいきませんでした。(詳細はここに記載されています)
で、今回の趣旨はPythonからのBulkInsertを試してみようというものです。
driverですが、前回は④を使いましたが、今回は②psycopg2を使ってみました。
事前に、
CREATE TABLE hash ( id text PRIMARY KEY , value text );
でhashテーブルというのを作っています。
ソースは以下みたいな感じです。
------ bulk insertする実行例 ------
#!/usr/bin/env python
import csv
import psycopg2
import time
if __name__ == '__main__':
start = time.time()
c = psycopg2.connect(host="localhost",user="postgres",password="xxxx",database="testdb")
i = 0
l = []
cur = c.cursor()
reader = csv.reader(open("./neta.csv"))
for row in reader:
id = row[0]
value = row[1]
t = (id,value)
l.append(t)
i += 1
if i % 10000 == 0:
cur.executemany("insert into hash values(%s,%s)",l)
c.commit()
cur = c.cursor()
l = []
c.commit()
c.close()
print time.time()-start
上記を実行すると100万件のinsertに大体200sかかりました。
因みに1件ずつinsertするのは以下のような感じです。
------ bulk insertしない実行例 ------
#!/usr/bin/env python
import csv
import psycopg2
import time
if __name__ == '__main__':
start = time.time()
c = psycopg2.connect(host="localhost",user="postgres",password="xxxx",database="testdb")
i = 0
reader = csv.reader(open("./neta.csv"))
for row in reader:
id = row[0]
value = row[1]
t = (id,value)
cur = c.cursor()
cur.execute("insert into hash values(%s,%s)",t)
i += 1
if i % 10000 == 0:
c.commit()
c.commit()
c.close()
print time.time()-start
これを実行すると100万件のinsertに220sかかりました。
executemany()を使用してもパフォーマンス改善にはさしてつながっていません。しかし、言い方を変えると20sも改善しています。これは通信のオーバヘッド以上に処理に時間がかかっている為、改善効果が大きくは見えないという事でしょう。
前回のpg8000で実施したテストよりもだいぶ高速だった為、pg8000でももう一度試してみました。上記のソースで、
・import psycopg2のところをimport pg8000とする
・psycopg2.connect のところを pg8000.dbapi.connectとする
事でつながるようになります。結果として以前やった結果と変わらずにbulkinsertを使おうが使うまいが、1000s以上かかってしまいます。理由は全く不明ですが、バインド変数とかをpg8000だとうまく使えて無いのかな・・・?
<まとめ>
・fedoraにpostgresqlのドライバをinstallする際はpython-develを入れるのを忘れずに
・psycopg2でbulkinsertの効果を確認したが、さしたる改善効果は無かった。
・pg8000とpsycopg2で大量insertのパフォーマンスを比較すると、psycopg2の方が圧倒的に早い。
2011年4月22日金曜日
2011年4月16日土曜日
PythonからSqlite3に大量データをinsertしてみた(その2)
PythonからSqliteに大量データをinsertする際に1件ずつinsertを行うのでは無く、Bulkinsertを行ったら、どの程度高速化されるかを確認しました。Pythonに組み込まれているsqlite3クラスにはexecutemany()というメソッドが実装されていて簡単でした。
事前にsqliteでtestdbというDBを作っておいて、
sqlite> CREATE TABLE hash ( id INTEGER PRIMARY KEY , value TEXT );
でhashというテーブルを作成しておきます。
その後、neta.csvというファイルの中身をhashテーブルにinsertしていきます。
------------------------------------------------------------------------------------------
事前にsqliteでtestdbというDBを作っておいて、
sqlite> CREATE TABLE hash ( id INTEGER PRIMARY KEY , value TEXT );
でhashというテーブルを作成しておきます。
その後、neta.csvというファイルの中身をhashテーブルにinsertしていきます。
------------------------------------------------------------------------------------------
#!/usr/bin/env python
import csv
import sqlite3
import time
if __name__ == '__main__':
start = time.time()
c = sqlite3.connect('./testdb')
i = 0
l = []
reader = csv.reader(open("./neta.csv"))
for row in reader:
id = row[0]
value = row[1]
t = (id,value)
l.append(t)
i += 1
if i % 200000 == 0:
c.executemany('insert into hash (id,value) values(?,?)',l)
c.commit()
l = []
c.commit()
c.close()
print time.time()-start
------------------------------------------------------------------------------------------
上記を実行したところ、13sで100万件のinsertが完了しました。
以前、1件ずつやった場合だと、27sだったので約2倍の高速化につながりました。
2011年4月9日土曜日
PostgreSQL9.0.3 のpsqlが使えなくてがっかりした
最近PostgreSQLを使ってなかったので、最新版(9.0.3)をFedora13(32bit)にinstallしてみました。尚、PostgreSQLのlinux版はEnterpriseDB社のページからダウンロードするように促される為、そこからファイルを落としてインストーラーを実行します。
インストール自体は何の問題がありませんでしたが、createdbを実行した後にpsqlコマンドにて軽く接続しようとすると以下のエラーが出て、全くつながりません。
--------------------------------------
-bash-4.1$ psql testdb
Password:
psql (9.0.3)
Type "help" for help.
Cannot read termcap database;
using dumb terminal settings.
Aborted (core dumped)
--------------------------------------
はっ?
何か環境設定が悪いのかなと思ったが、特に悪いところは見当たらない。
ので調べると、どうやら既知のバグのようである。
BUG #5807: psql fails to launch with "Cannot read termcap database; using dumb terminal settings. Aborted"
尚、対象のBUGの環境はUbuntuとだけ記載されている。9.0.2から中身が変わっていて出るようになったのだろうとの事。
また、この話題ではPostgreSQLのMLは盛り上がって無かった。
Redhat とか CentOSだと問題の無い話なんでしょうか。
肝心の解決方法はさらっととしか記載が無かったし、9.0.3でも改善していないので少しがっかりですが、
LD_PRELOAD=/lib/libreadline.so.6
を追加したらうまくいく・・・との事。
実際これでうまくいきました。
しかし、PostgreSQLのMLの議論では以下のようにありました。
There was a change in 9.0.2 to use libedit instead of readline for this (readline is GPL, which is not acceptable to some people who wish to use Postgres in other products).
つまり、9.0.2からはreadlineを使わないように修正したんだけど、回避方法はreadlineを無理やり使おう・・・という事のように読み取れます。
全般的に何だかなーというところです。
インストール自体は何の問題がありませんでしたが、createdbを実行した後にpsqlコマンドにて軽く接続しようとすると以下のエラーが出て、全くつながりません。
--------------------------------------
-bash-4.1$ psql testdb
Password:
psql (9.0.3)
Type "help" for help.
Cannot read termcap database;
using dumb terminal settings.
Aborted (core dumped)
--------------------------------------
はっ?
何か環境設定が悪いのかなと思ったが、特に悪いところは見当たらない。
ので調べると、どうやら既知のバグのようである。
BUG #5807: psql fails to launch with "Cannot read termcap database; using dumb terminal settings. Aborted"
尚、対象のBUGの環境はUbuntuとだけ記載されている。9.0.2から中身が変わっていて出るようになったのだろうとの事。
また、この話題ではPostgreSQLのMLは盛り上がって無かった。
Redhat とか CentOSだと問題の無い話なんでしょうか。
肝心の解決方法はさらっととしか記載が無かったし、9.0.3でも改善していないので少しがっかりですが、
LD_PRELOAD=/lib/libreadline.so.6
を追加したらうまくいく・・・との事。
実際これでうまくいきました。
しかし、PostgreSQLのMLの議論では以下のようにありました。
There was a change in 9.0.2 to use libedit instead of readline for this (readline is GPL, which is not acceptable to some people who wish to use Postgres in other products).
つまり、9.0.2からはreadlineを使わないように修正したんだけど、回避方法はreadlineを無理やり使おう・・・という事のように読み取れます。
全般的に何だかなーというところです。
2011年4月3日日曜日
PythonでMongoDBに大量のデータをinsertしてみた(その2)
以前MongoDBに大量データをinsertしてみましたが、まとめてinsertした場合、どの程度効果があるのか確認してみました。MongoDBは最新版のv1.8.0です。
つまり、1000件ずつまとめてinsertする方が2倍以上高速に動作しているようです。
因みにですが、MongoDBv1.8からジャーナルモードをサポートしているようです。RDBのように、変更履歴を先にLogファイルとして書き出し、耐障害性の向上を目指しているようです。そうすると、パフォーマンスは落ちるのだろうなーと思って実験してみました。
まず、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モードで無い場合よりも、"ある程度"向上するだけ。という事かなと思いました。
./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モードで無い場合よりも、"ある程度"向上するだけ。という事かなと思いました。
登録:
投稿 (Atom)