CouchDB And MongoDB Performance
I wanted to follow up yesterday's detailed (and objective?) post on CouchDB with some basic benchmarks. I know people hate these types of benchmarks. But I do think it's good to have some very high level idea about these things. Also, both CouchDB and MongoDB have a bulk-api, which is useful for some tasks, but I think most web apps are dealing with fairly small and independent pieces of information. The code is a very poor simulation of the two main queries used in a game engine.
For the record, journaling is enabled in MongoDB and I'm doing a full fscync on each insert (the ruby driver doesn't support journal commit yet (which would be faster than a full data file fsync)?! guess what I'm doing next...)
The MongoDB code:
require 'mongo'
require 'benchmark'
db = Mongo::Connection.new.db("test")
app_ids = Array.new(10){|i| BSON::ObjectId.new}
scores = db.collection("scores")
scores.ensure_index([['appid', Mongo::ASCENDING], ['points', Mongo::DESCENDING]])
Benchmark.bm do |x|
x.report do
10000.times do |i|
if i % 2 == 0
scores.insert({:appid => app_ids.sample, :points => rand(100000), :dated => Time.now - rand(100000), :user => i.to_s}, {:safe => true, :fsync => true})
else
scores.find({:appid => app_ids.sample}).sort([:points, :descending]).limit(20).skip(rand(20)).to_a
end
end
end
end
user system total real
6.600000 1.040000 7.640000 ( 12.290563)
The CouchDB code:
require 'couchdb'
require 'uuid'
require 'benchmark'
server = CouchDB::Server.new 'localhost', 5984
database = CouchDB::Database.new server, 'test'
database.delete_if_exists!
database.create_if_missing!
app_ids = Array.new(10){|i| UUID.new.generate}
design = CouchDB::Design.new database, 'application'
view = CouchDB::Design::View.new design, 'scores_by_points', 'function(doc) { emit([doc.appid, doc.points], null); }'
design.save
Benchmark.bm do |x|
x.report do
10000.times do |i|
if i % 2 == 0
doc = CouchDB::Document.new database, :appid => app_ids.sample, :points => rand(100000), :dated => Time.now - rand(100000), :user => i.to_s
doc.save
else
app_id = app_ids.sample
scores = view.collection(:startkey => [app_id], :endkey => [app_id,{}], :descending => false, :limit => 10, :include_docs => true)
scores[0] # i believe the data isn't loaded until you actually request the 1st item
end
end
end
end
user system total real
22.800000 6.040000 28.840000 (177.352028)
Again, being a CouchDB nub, I possibly did something very stupid (beyond running and posting yet another stupid benchmark), so I welcome any corrections to the code
Oh, and I know my blog dates are wrong...it's a mistake which has proven a slippery slope