sql >> Database teknologi >  >> NoSQL >> MongoDB

Mongoengine er meget langsom på store dokumenter sammenlignet med indfødt pymongo-brug

TL;DR:mongoengine bruger aldre på at konvertere alle de returnerede arrays til dicts

For at teste dette opbyggede jeg en samling med et dokument med et DictField med en stor indlejret dict . Dokumentet er cirka i dit 5-10 MB rækkevidde.

Vi kan derefter bruge timeit.timeit for at bekræfte forskellen i læsninger ved hjælp af pymongo og mongoengine.

Vi kan derefter bruge pycallgraph og GraphViz at se, hvad der tager mongoengine så lang tid.

Her er koden i sin helhed:

import datetime
import itertools
import random
import sys
import timeit
from collections import defaultdict

import mongoengine as db
from pycallgraph.output.graphviz import GraphvizOutput
from pycallgraph.pycallgraph import PyCallGraph

db.connect("test-dicts")


class MyModel(db.Document):
    date = db.DateTimeField(required=True, default=datetime.date.today)
    data_dict_1 = db.DictField(required=False)


MyModel.drop_collection()

data_1 = ['foo', 'bar']
data_2 = ['spam', 'eggs', 'ham']
data_3 = ["subf{}".format(f) for f in range(5)]

m = MyModel()
tree = lambda: defaultdict(tree)  # http://stackoverflow.com/a/19189366/3271558
data = tree()
for _d1, _d2, _d3 in itertools.product(data_1, data_2, data_3):
    data[_d1][_d2][_d3] = list(random.sample(range(50000), 20000))
m.data_dict_1 = data
m.save()


def pymongo_doc():
    return db.connection.get_connection()["test-dicts"]['my_model'].find_one()


def mongoengine_doc():
    return MyModel.objects.first()


if __name__ == '__main__':
    print("pymongo took {:2.2f}s".format(timeit.timeit(pymongo_doc, number=10)))
    print("mongoengine took", timeit.timeit(mongoengine_doc, number=10))
    with PyCallGraph(output=GraphvizOutput()):
        mongoengine_doc()

Og outputtet beviser, at mongoengine er meget langsom sammenlignet med pymongo:

pymongo took 0.87s
mongoengine took 25.81118331072267

Den resulterende opkaldsgraf illustrerer ret tydeligt, hvor flaskehalsen er:

I bund og grund vil mongoengine kalde to_python-metoden på hvert DictField at den kommer tilbage fra db. to_python er ret langsom, og i vores eksempel bliver det kaldt et sindssygt antal gange.

Mongoengine bruges til elegant at kortlægge din dokumentstruktur til python-objekter. Hvis du har meget store ustrukturerede dokumenter (hvilket mongodb er fantastisk til), så er mongoengine ikke rigtigt det rigtige værktøj, og du bør bare bruge pymongo.

Men hvis du kender strukturen, kan du bruge EmbeddedDocument felter for at få lidt bedre ydeevne fra mongoengine. Jeg har kørt en lignende, men ikke tilsvarende test kode i denne oversigt og outputtet er:

pymongo with dict took 0.12s
pymongo with embed took 0.12s
mongoengine with dict took 4.3059175412661075
mongoengine with embed took 1.1639373211854682

Så du kan lave mongoengine hurtigere, men pymongo er meget hurtigere endnu.

OPDATERING

En god genvej til pymongo-grænsefladen her er at bruge aggregeringsrammen:

def mongoengine_agg_doc():
    return list(MyModel.objects.aggregate({"$limit":1}))[0]



  1. Hvad skal jeg vælge:MongoDB/Cassandra/Redis/CouchDB?

  2. Mongo svarende til SQL's SELECT DISTINCT?

  3. Mongo Copy Collection og brugertilladelser

  4. MongoDB gruppe efter varighed span