Skip to content

Instantly share code, notes, and snippets.

@avichalp
Last active December 9, 2022 18:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save avichalp/7de5cf31ac54f268de219e84ab72049a to your computer and use it in GitHub Desktop.
Save avichalp/7de5cf31ac54f268de219e84ab72049a to your computer and use it in GitHub Desktop.
Embedded databases benchmarks

@coleifer: Did some simple benchmarking of embedded databases in python. It was done in with the following environment:

  • Linux 3.14.4
  • Python 2.7.7 (Py2K 4 lyfe!)
  • SSD

I have modified his script for python 3.5 and run the script against sd card. My environment is:

  • Linux 4.4.38
  • Python 3.5.2
  • SD card
  • ARM v7

Testing with N = 100000

UnQLite

Writes: 2.444714069366455 Reads: 1.6616613864898682

UnQLiteJSON

Writes: 3.617347478866577 Reads: 2.1200473308563232

Vedis

Writes: 2.357679605484009 Reads: 1.624964714050293

VedisKV

Writes: 2.47371244430542 Reads: 1.6631860733032227

GDBM

Writes: 3.0294344425201416 Reads: 1.49436616897583

BDBBTree

Writes: 8.086156606674194 Reads: 4.68268609046936

BDBHashTable

Writes: 9.237087488174438 Reads: 5.801295757293701

KyotoBTree

Writes: 1.4112212657928467 Reads: 1.4075307846069336

KyotoHashTable

Writes: 1.5034441947937012 Reads: 1.3784515857696533

LevelDB

Writes: 2.7352421283721924 Reads: 1.335801362991333

Sqlite

Writes: 1267.9827723503113 Reads: 7.064197301864624

import os
import time
from unqlite import UnQLite
from vedis import Vedis
import bsddb3
import dbm.gnu as gdbm
import kyotocabinet as kc
import plyvel
import sqlite3
def timed(fn):
def inner(*args):
s = time.time()
fn(*args)
return time.time() - s
return inner
class Test(object):
def __init__(self, n):
self.n = n
if os.path.exists(self.filename):
if os.path.isdir(self.filename):
os.removedirs(self.filename)
else:
os.unlink(self.filename)
self._db = self.get_db()
def close(self):
try:
self._db.close()
except AttributeError:
pass
@timed
def test_writes(self):
for i in range(self.n):
self.write(str(i))
@timed
def test_reads(self):
for i in range(self.n):
self.read(str(i))
def write(self, i):
self._db[i] = i
def read(self, i):
return self._db[i]
class UnQLiteTest(Test):
filename = '/tmp/unq.db'
def get_db(self):
return UnQLite(self.filename)
class UnQLiteJSONTest(Test):
filename = '/tmp/unq-json.db'
def get_db(self):
db = UnQLite(self.filename)
self.coll = db.collection('values')
self.coll.create()
@timed
def test_writes(self):
data = [{str(i): i} for i in range(self.n)]
self.coll.store(data)
@timed
def test_reads(self):
return self.coll.all()
class VedisTest(Test):
filename = '/tmp/vedis.db'
def get_db(self):
return Vedis(self.filename)
class VedisKVTest(Test):
filename = '/tmp/vediskv.db'
def write(self, i):
self._db.store(i, i)
def read(self, i):
return self._db.fetch(i)
def get_db(self):
return Vedis(self.filename)
class GDBMTest(Test):
filename = '/tmp/gdbm.db'
def get_db(self):
return gdbm.open(self.filename, 'c')
class BDBBTreeTest(Test):
filename = '/tmp/bdb_btree.db'
def get_db(self):
return bsddb3.btopen(self.filename)
def write(self, i):
self._db[bytes(i, "utf-8")] = bytes(i, "utf-8")
def read(self, i):
return self._db[bytes(i, "utf-8")]
class BDBHashTableTest(Test):
filename = '/tmp/bdb_hashtable.db'
def get_db(self):
return bsddb3.hashopen(self.filename)
def write(self, i):
self._db[bytes(i, "utf-8")] = bytes(i, "utf-8")
def read(self, i):
return self._db[bytes(i, "utf-8")]
class KyotoBTreeTest(Test):
filename = '/tmp/kyoto_btree.kct'
def get_db(self):
db = kc.DB()
db.open(self.filename, kc.DB.OWRITER | kc.DB.OCREATE)
return db
def write(self, i):
self._db.set(i, i)
def read(self, i):
return self._db.get(i)
class KyotoHashTableTest(Test):
filename = '/tmp/kyoto_hashtable.kch'
def get_db(self):
db = kc.DB()
db.open(self.filename, kc.DB.OWRITER | kc.DB.OCREATE)
return db
def write(self, i):
self._db.set(i, i)
def read(self, i):
return self._db.get(i)
class LevelDBTest(Test):
filename = '/tmp/leveldb.db'
def get_db(self):
return plyvel.DB(self.filename, create_if_missing=True)
def write(self, i):
self._db.put(bytes(i, "utf-8"), bytes(i, "utf-8"))
def read(self, i):
return self._db.get(bytes(i, "utf-8"))
class RocksDBTest(Test):
filename = '/tmp/rocksdb.db'
def get_db(self):
return rocksdb.DB(self.filename,
rocksdb.Options(create_if_missing=True))
def write(self, i):
self._db.put(i, i)
def read(self, i):
self._db.get(i)
class SqliteTest(Test):
filename = '/tmp/sqlite.db'
def get_db(self):
db = sqlite3.connect(self.filename)
self._cursor = db.cursor()
self._cursor.execute("""
create table data (
key varchar(255) not null primary key,
value varchar(255) not null
);
""")
return db
def write(self, i):
self._cursor.execute("INSERT INTO data (key, value) VALUES (?, ?)",
(i, i))
self._db.commit()
def read(self, i):
self._cursor.execute("SELECT * FROM data WHERE key=?", (i,))
self._cursor.fetchall()
class RedisTest(Test):
filename = '/tmp/na'
def get_db(self):
db = Redis(db=15)
db.flushdb()
return db
tests = [
UnQLiteTest,
UnQLiteJSONTest,
VedisTest,
VedisKVTest,
GDBMTest,
BDBBTreeTest,
BDBHashTableTest,
KyotoBTreeTest,
KyotoHashTableTest,
LevelDBTest,
SqliteTest,
]
N = 100000
print('Testing with N = %s' % N )
print( '------------------------------------' )
print('\n\n')
for TestClass in tests:
test_name = TestClass.__name__.replace('Test', '')
print( test_name )
print( '~' * len(test_name))
test = TestClass(N)
print( 'Writes: ', test.test_writes())
print( 'Reads: ', test.test_reads())
print('\n')
test.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment