TL; DR: mongoengine verbringt Alter aller zurückgegebenen Arrays dicts
Umwandlung Um dies zu testen, ich eine Sammlung mit einem Dokument mit einem DictField
mit einer großen verschachtelten dict
gebaut. Das Dokument liegt ungefähr im Bereich von 5-10 MB.
Wir können dann timeit.timeit
verwenden, um den Unterschied in Lesevorgänge mit Pymongo und Mongoengine zu bestätigen.
Wir können dann pycallgraph und GraphViz verwenden, um zu sehen, was mongoengine so verdammt lange dauert. Hier
ist der Code in voller Länge:
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()
Und der Ausgang beweist, dass mongoengine ist sein sehr langsam im Vergleich zu pymongo:
pymongo took 0.87s
mongoengine took 25.81118331072267
Das resultierende Aufrufdiagramm zeigt recht deutlich, wo der Flaschenhals ist:
Im Wesentlichen wird Mongoengine die Methode to_python auf jeder DictField
aufrufen, die es von der db zurückerhält. to_python
ist ziemlich langsam und in unserem Beispiel wird es eine wahnsinnige Anzahl von Zeiten genannt.
Mongoengine wird verwendet, um Ihre Dokumentstruktur elegant Python-Objekten zuzuordnen. Wenn Sie sehr große unstrukturierte Dokumente haben (für die mongodb ist großartig), dann Mongoengine ist nicht wirklich das richtige Werkzeug und Sie sollten nur Pymongo verwenden.
Wenn Sie jedoch die Struktur kennen, können Sie EmbeddedDocument
Felder verwenden, um etwas bessere Leistung von Mongoengine zu bekommen.Ich habe einen ähnlichen, aber nicht gleichwertig Test laufe code in this gist und der Ausgang ist:
pymongo with dict took 0.12s
pymongo with embed took 0.12s
mongoengine with dict took 4.3059175412661075
mongoengine with embed took 1.1639373211854682
So können Sie mongoengine schneller machen, aber pymongo ist noch viel schneller.
UPDATE
Eine gute Verknüpfung zum pymongo Schnittstelle hier ist die Aggregation Framework zu verwenden:
def mongoengine_agg_doc():
return list(MyModel.objects.aggregate({"$limit":1}))[0]
Es gibt zwei verschieden scheint Dinge. Native Methode lädt 1 Dokument und stoppt, während Mongoengine alle Dokumente lädt und die erste zurückgibt. Versuchen Sie, von 'find_one()' zu 'list (db.collection.find()) [0]' zu gleichen Methoden zu wechseln. – Valijon
Ich habe auch versucht, Limit (1) in der Mongoengine Abfrage hinzuzufügen, es hat nicht geholfen. Scheint, dass die meiste Zeit damit verbracht wird, das mongoengine Document-Objekt mit allen verschachtelten Objekten zu erstellen. –
'skip' und' limit' funktionieren, sobald Dokumente geladen sind :(Versuche nach spezifischen Abfragen zu filtern ... [http://docs.mongoengine.org/guide/querying.html#query-operators](http://docs.mongoengine.org/guide/querying.html#query-operators) – Valijon