最大1000件程度のデータを処理するためののデータベースは何がいいか。 シェルスクリプトからも気軽に操作できて、 いざとなればテキストエディタでデータの一部をごにょっと変更できるような、 そんなデータベースを構築したい。候補は SQLite3 で、 テキストエディタでデータをいじるための wrapper である visq3 も作って準備万端にしていたのだが、ちょっと待ったを掛けて もっといいものの可能性を検討してからにしたい。
最近YAMLのスッキリした可読性に惹かれていて、 YAMLでも行けるならそれがいいかなと思ってこの実験を始めた。 YAMLとPStore(Ruby固有)にはtransactionの概念があって、 プログラマが気にしなくても排他制御やロールバックをしてくれる。 小規模データベースとしてものすごく使いやすい。
今回の要件をまとめると
となる。ざっとみた限り、シェルスクリプトからも使いやすいとなると SQLite3とYAMLの一騎打ちという感じなのだが せっかくなので、近傍のデータ処理系を実験対象に入れてみた。
候補 | データの可読性 | トランザクション提供 | データの汎用性 | 速度 |
---|---|---|---|---|
SQLite3 | ×(でもvisq3でカバー) | ○ | ○ | ◎ |
PStore | ×(要コンバータ) | ○(Ruby/JSON) | ○ | ? |
YAML | ◎(一番好み) | ○(Ruby/yaml) | ○ | ? |
JSON | ○ | ×(Ruby/JSON) | ○ | ? |
CSV | ○ | ×(Ruby/CSV) | ◎ | ? |
意外にもJSONライブラリにトランザクションがなかった(あるの?)。 もともとデータベースとして使うと言うより シリアライズしたデータの受け渡しが主眼なのでそういうもんか。 読み込みと書き出しを個別に行なう必要があるのは CSVライブラリもいっしょで、自前で排他制御などする必要があるため面倒臭い。 将来自分のコードを忘れて機能修正するときを考えるとちょっといやん。
速度が分からないので調べてみた。
通常1000件程度で最大でも1万件は行かないことは分かっているので 間を取ってちょっと上の7000件のデータで実験。
レコード数 | 7000 |
---|---|
1レコードあたりのバイト数 | 約500B |
フィールド数 | 9 |
測定機は AMD Opteron 3280(8C 2.4GHz) でデータをNFS上に置いた。 データは高々数MBなのでローカルディスクに置いても大差ないだろう。
まず、mkdummy.zsh でダミーデータ(dummy.csv)を生成。これを元に SQLite3, PStore, YAML, JSON, CSV の初期データを db-test.rb で作成。
for v in SQ3 PST YAML JSON CSV; do
time env ${v}=1 ./do-test.rb init
done
あ、もうここで速度にかなりの差が。すでにこの段階で 更新時間のテストをやる気分が薄れてしまったが気を取り直して...
7000件レコードを読み出してそのうちの第2フィールドの値を ちょっとだけ書き変えて保存する実験。
for v in SQ3 PST YAML JSON CSV; do
time env ${v}=1 ./do-test.rb
done
更新対象 | 更新時間 | 所要時間(total) |
---|---|---|
SQLite3 | 0.58 | 0.83 |
PStore | 2.64 | 2.91 |
YAML | 28.88 | 29.26 |
JSON | 2.04 | 2.31 |
CSV | 4.21 | 4.46 |
ぬぬ、ひいきのYAML遅いな。残念。あとJSONはえー。 内部コードに落とすPStoreに勝ってるのはさすがだが、このくらいの差なら transactionの安心感でPStoreを選んじゃうかも。あとCSV健闘。 2倍程度遅いだけならJSONよりCSVてのもありだ。でも排他処理欲しい。 ちなみに表中のSQLite3の0.58秒てのはちょっとハンデを負わせていて、 必要ないのに7000件全レコードを読ませてから更新処理している。 通常のSQL処理のように必要なレコードのみの更新をすると以下のとおり圧勝。
time SQ3=sel ./do-test.rb
Updation took 0.05s
SQ3=sel ./do-test.rb 0.25s user 0.00s system 82% cpu 0.301 total
更新時間0.05秒。まあそういうことで、 YAMLではなくSQLite3にするふん切りが付いた。