2010/12/15

CouchDB: group_numrows拡張のパフォーマンス

修正したコードを使ってVMWare上のCouchDBサーバに対して、118,924件の郵便番号を数えた場合の速度を比較してみました。

元々のDBの構造はCSVファイルを1文書に変換したもので、詳細は 以前の記事にあります。

その他のmap/reduce関数の定義、データ取得用スクリプトは次のとおりです。

viewを作成するためのmap,reduce関数

json['views']['code']['map'] = <<-MAP
function(doc) {
  if(doc._id.length == 40) {
    emit(doc.code, 1)
  }
}
MAP
json['views'][label]['reduce'] = "_sum"

使用したRubyスクリプト

#!/usr/local/bin/ruby
# -*- coding: utf-8 -*-

require 'csv'
require 'couchdb'
require 'json'
require 'uri'

couch = Couch::Server.new("localhost","5984")

def show(couch, uri)
begin
  res = couch.get(URI.escape(uri))
  json = JSON.parse(res.body)
p json['group_numrows'] if json.has_key?('group_numrows')
p json['rows'].length if json.has_key?('rows')
rescue
  p $!
end
end
#uri = YaCouch::DBname + '/_design/all/_view/code?group=true'
#show(couch, uri)
uri = YaCouch::DBname + '/_design/all/_view/code?group=true&group_numrows=true'
show(couch, uri)

これにtimeコマンドを使って実行速度を測ってみました。

VMWareを使うとディスクアクセスは特にホストOSのファイルキャッシュの影響を強く受ける傾向があると感じているので、何回か両方のスクリプトを実行した後に計測を始め、各2回目の結果を載せています。

Array.lengthを使って重複を取り除いたキーの数を数える方法

配列の数を数え上げるわけですが、各要素は、 {"key"=>"9998524", "value"=>1}、のような形式になっています。

118924

real	0m8.183s
user	0m4.188s
sys	0m3.812s

group_numrowsパラメータでCouchDBから取得する方法

この戻り値は単純で、クライアントが受け取るのは、 {"group_numrows":"118924"}の一行だけです。 スクリプトの最後の4行のコメントを変更して、同じように実行しています。

"118924"

real	0m0.952s
user	0m0.132s
sys	0m0.052s

Array.lengthを計算しない、JSON.parseを実行しない場合の速度

スクリプトをちょっと変更して、res = couch.get(URI.escape(uri))行の次にreturnを挿入して、すぐに戻るようにしてみました。

real	0m7.796s
user	0m3.784s
sys	0m3.836s

今回の環境では、ほとんどネットワークトラフィックの影響が時間に大きな影響を与えていて、JSON.parse()自体が時間を取っているわけではない事がわかります。

まとめ

この後に実環境でも試しましたが、おおむね同じような結果になりました。

ただし、group_numrowsを使った場合の実時間が最大1.4[s]程度、配列を取得する場合の時間が最小5.7[s]程度となり、その差は縮まっています。

erlangの軽量プロセスについて、もう少し勉強して何か不備はないか確認しようと思います。

0 件のコメント: