Skip to content

Instantly share code, notes, and snippets.

@amcgregor
Created September 6, 2017 03:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save amcgregor/ef40e88b3b0dbf0af1cb75a6934b89c2 to your computer and use it in GitHub Desktop.
Save amcgregor/ef40e88b3b0dbf0af1cb75a6934b89c2 to your computer and use it in GitHub Desktop.
An ugly, ugly, but very specific phased benchmark comparison between MongoEngine and Marrow Mongo regarding MongoEngine/mongoengine#1624

Benchmark Results

From MongoEngine/mongoengine#1624

Python 3.6.2

MongoEngine 0.14.0 Pre-Optimization

Master branch @ dc8a64fa7d00364956560d47a7b753aee84fa561

  • Population: 0.04223203659057617 seconds
  • Insertion (instance.save): 0.37940502166748047 seconds
  • Interrogation: 5.322256803512573 seconds
  • Deserialization: 0.16296911239624023 seconds

MongoEngine 0.14.0 Post-Optimization

Master branch @ 5bdd35464b89dd2def1dcb0464e244322f1bc757

  • Population: 0.037187814712524414 seconds
  • Insertion (instance.save): 0.3511490821838379 seconds
  • Interrogation: 3.0043630599975586 seconds
  • Deserialization: 0.12032485008239746 seconds

Timeit

  • Population: 28.7 ms ± 1.61 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
  • Interrogation: 2.69 s ± 48.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • Deserialization: 62.3 ms ± 3.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Marrow Mongo 1.1.2

  • Population: 0.1457810401916504 seconds
  • Interrogation: 1.714001178741455 seconds
  • Insertion (instance.insert_one): 0.27471399307250977 seconds
  • Insertion (collection.insert_one): 0.25157928466796875 seconds
  • Insertion (collection.insert_many): 0.0812380313873291 seconds
  • Deserialization: 0.0743868350982666 seconds

Timeit

  • Population: 148 ms ± 5.28 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
  • Interrogation: 1.75 s ± 40.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • Deserialization: 59.2 ms ± 1.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
# encoding: utf-8
from __future__ import unicode_literals
from itertools import chain
from time import time
print("### MongoEngine\n")
from mongoengine import connect, Document, IntField, StringField, ListField, ReferenceField
db = connect('test').test
class MEProduct(Document):
product_number = IntField()
class MEProductFamily(Document):
name = StringField()
products = ListField(ReferenceField(MEProduct))
class MEOrder(Document):
product = ReferenceField(MEProduct)
def populate_me():
products = [MEProduct(product_number=i) for i in range(300)]
return (products,
[MEProductFamily(name=str(i), products=products[i:i+5]) for i in range(295)],
[MEOrder(product=products[i]) for i in range(300)])
def populate_me_insert():
products = [MEProduct(product_number=i).save(force_insert=True) for i in range(300)]
return (products,
[MEProductFamily(name=str(i), products=products[i:i+5]).save(force_insert=True) for i in range(295)],
[MEOrder(product=products[i]).save(force_insert=True) for i in range(300)])
def interrogate_me(products, families, orders):
result = {}
for family in families:
result[family.name] = [order for order in orders if order.product in family.products]
return result
def fetch_me():
seen = None
for i in MEProduct.objects.no_cache().no_dereference():
seen = i
for i in MEProductFamily.objects.no_cache().no_dereference():
seen = i
for i in MEOrder.objects.no_cache().no_dereference():
seen = i
return seen
start = time()
populate_me()
delta = time() - start
print('* **Population:** {} seconds'.format(delta))
start = time()
products, families, orders = populate_me_insert()
idelta = time() - start
print('* **Insertion (`instance.save`):** {} seconds'.format(idelta - delta))
start = time()
interrogate_me(products, families, orders)
end = time()
print('* **Interrogation:** {} seconds'.format(end - start))
start = time()
fetch_me()
end = time()
print('* **Deserialization:** {} seconds'.format(end - start))
del products, families, orders
print("\n## Marrow Mongo 1.1.2\n")
from marrow.mongo.trait import Queryable
from marrow.mongo.field import Integer, String, Array, Reference
class MMProduct(Queryable):
__collection__ = 'products'
product_number = Integer()
class MMProductFamily(Queryable):
__collection__ = 'families'
name = String()
products = Array(Reference(MMProduct))
class MMOrder(Queryable):
__collection__ = 'orders'
product = Reference(MMProduct)
MMProduct.bind(db)
MMProductFamily.bind(db)
MMOrder.bind(db)
def populate_mm():
products = [MMProduct(product_number=i) for i in range(300)]
return (products,
[MMProductFamily(name=str(i), products=products[i:i+5]) for i in range(295)],
[MMOrder(product=products[i]) for i in range(300)])
def insert_mm_record(products, families, orders):
for record in chain(products, families, orders):
record.insert_one()
def insert_mm_collection(products, families, orders):
collection = MMProduct.get_collection()
for record in products:
collection.insert_one(record)
collection = MMProductFamily.get_collection()
for record in families:
collection.insert_one(record)
collection = MMOrder.get_collection()
for record in orders:
collection.insert_one(record)
def insert_mm_many(products, families, orders):
MMProduct.get_collection().insert_many(products)
MMProductFamily.get_collection().insert_many(families)
MMOrder.get_collection().insert_many(orders)
def fetch_mm():
seen = None
for i in MMProduct.find():
seen = MMProduct.from_mongo(i)
for i in MMProductFamily.find():
seen = MMProductFamily.from_mongo(i)
for i in MMOrder.find():
seen = MMOrder.from_mongo(i)
return seen
start = time()
products, families, orders = populate_mm()
end = time()
print('* **Population:** {} seconds'.format(end - start))
start = time()
interrogate_me(products, families, orders)
end = time()
print('* **Interrogation:** {} seconds'.format(end - start))
start = time()
insert_mm_record(products, families, orders)
end = time()
print('* **Single Insertion (instance.insert_one):** {} seconds'.format(end - start))
MMProduct.get_collection().drop()
MMProductFamily.get_collection().drop()
MMOrder.get_collection().drop()
start = time()
insert_mm_collection(products, families, orders)
end = time()
print('* **Single Insertion (collection.insert_one):** {} seconds'.format(end - start))
MMProduct.get_collection().drop()
MMProductFamily.get_collection().drop()
MMOrder.get_collection().drop()
start = time()
insert_mm_many(products, families, orders)
end = time()
print('* **Multiple Insertion:** {} seconds'.format(end - start))
start = time()
fetch_mm()
end = time()
print('* **Deserialization:** {} seconds'.format(end - start))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment