Skip to content

Instantly share code, notes, and snippets.

@juliangruber
Created November 18, 2012 12:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juliangruber/4105078 to your computer and use it in GitHub Desktop.
Save juliangruber/4105078 to your computer and use it in GitHub Desktop.
LevelUp Leveled comparison

Levelup Leveled comparison

This is only for speed, Levelup provides some nice streaming abstractions that Leveled doesn't have.

Every benchmarked operation has to deal with 120000 entries, 29 chars each. Times were averaged from 3 runs.

The 2nd benchmark's output includes the factor of which leveled is faster/slower.

$ node levelup.js
put             3348 ms
batch           1955 ms
get             1846 ms
get ReadStream  5322 ms
get keyStream   5829 ms

$ node leveled.js
put             1121 ms (2.99x)
batch            230 ms (8.50x)
get             1446 ms (1.28x)
get find         309 ms (5.97x)
var leveled = require('leveled')
var assert = require('assert')
var db = leveled('/tmp/leveled.db/')
// insert 120000 values
function put (cb) {
var received = 0
for (var i = 0; i < 120000; i++) {
db.put(i, '1337,1337,1337,1337,1337,1337', function (err) {
if (err) throw err
if (++received == 120000) cb()
})
}
}
// insert 120000 values batched
function batch (cb) {
var batch = db.batch()
for (var i = 0; i < 120000; i++) {
batch.put(i, '1337,1337,1337,1337,1337,1337')
}
batch.write(function (err) {
if (err) throw err
cb()
})
}
// read 120000 values
function get(cb) {
var received = 0
for (var i = 0; i < 120000; i++) {
db.get(i, function (err, val) {
if (err) throw err
assert(val == '1337,1337,1337,1337,1337,1337')
if (++received == 120000) cb()
})
}
}
// read 120000 keys through find
function find (cb) {
db.find('*', function (err, res) {
if (err) throw err
Object.keys(res).forEach(function (key) {
assert(res[key] == '1337,1337,1337,1337,1337,1337')
})
cb()
})
}
// get started
var start = Date.now()
put(function () {
console.log('put', Date.now() - start, 'ms')
start = Date.now()
batch(function () {
console.log('batch', Date.now() - start, 'ms')
start = Date.now()
get(function () {
console.log('get', Date.now() - start, 'ms')
start = Date.now()
find(function () {
console.log('get find', Date.now() - start, 'ms')
})
})
})
})
var levelup = require('levelup')
var assert = require('assert')
var db = levelup('/tmp/levelup.db/', { createIfMissing : true })
// insert 120000 values
function put (cb) {
var received = 0
for (var i = 0; i < 120000; i++) {
db.put(i, '1337,1337,1337,1337,1337,1337', function (err) {
if (err) throw err
if (++received == 120000) cb()
})
}
}
// insert 120000 values batched
function batch (cb) {
var ops = []
for (var i = 0; i < 120000; i++) {
ops.push({ type : 'put', key : i, value : '1337,1337,1337,1337,1337,1337' })
}
db.batch(ops, function (err) {
if (err) throw err
cb()
})
}
// read 120000 values
function get(cb) {
var received = 0
for (var i = 0; i < 120000; i++) {
db.get(i, function (err, val) {
if (err) throw err
assert(val == '1337,1337,1337,1337,1337,1337')
if (++received == 120000) cb()
})
}
}
// read 120000 values through stream
function readStream (cb) {
db.readStream()
.on('data', function (data) {
assert(data.value == '1337,1337,1337,1337,1337,1337')
})
.on('error', function (err) {
throw err
})
.on('end', cb)
}
// read 120000 keys through stream
function keyStream (cb) {
db.keyStream()
.on('data', function (data) {
})
.on('error', function (err) {
throw err
})
.on('end', cb)
}
// get started
var start = Date.now()
put(function () {
console.log('put', Date.now() - start, 'ms')
start = Date.now()
batch(function () {
console.log('batch', Date.now() - start, 'ms')
start = Date.now()
get(function () {
console.log('get', Date.now() - start, 'ms')
start = Date.now()
readStream(function () {
console.log('get ReadStream', Date.now() - start, 'ms')
start = Date.now()
keyStream(function () {
console.log('get keyStream', Date.now() - start, 'ms')
})
})
})
})
})
@dominictarr
Copy link

Wow, this is quite a substantial difference.
It's impressive that your batch / find operations are about 10 times faster.

also, your put operation is also faster! what do you do differently that makes it faster?

@rvagg
Copy link

rvagg commented Nov 18, 2012

Not handling arbitrary data types and restricting both keys and values to strings certainly helps, LevelUP does Buffer conversions in JS but that could be moved to C++ & also there's probably too many to-buffer conversions where in many cases using the plain string will do. Also in general LevelUP is doing a ton more safety & type checking than Leveled.

thanks for the benchmarks @juliangruber, it's a great start.

@juliangruber
Copy link
Author

@dominictarr: batch is faster because it goes straight to C and builds the batch object there. With levelUP you first create that big array, then convert it to a batch object. find is faster because it again does everything in C and only hands out the finished array to javascript which might cause problems with big result sets, that streaming could solve. Don't know why put is faster, I think @rvagg made it even faster in levelUP already.

@rvagg: mhm, I evaluated buffers but even if you deal with them in C they're slower than strings. Does levelUP really need buffers? I know that it's more correct but strings work most of the time too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment