Mongoengine ist bei großen Dokumenten sehr langsam im Vergleich zur nativen Pymongo-Nutzung

8

Ich habe das folgende Mongoengine-Modell:

%Vor%

In einigen Fällen kann das Dokument in der DB sehr groß sein (etwa 5-10 MB), und die data_dict-Felder enthalten komplexe verschachtelte Dokumente (Diktatlisten, usw.).

Ich habe zwei (möglicherweise verwandte) Probleme festgestellt:

  1. Wenn ich die native pymongo find_one () -Abfrage ausführe, kommt sie innerhalb einer Sekunde zurück. Wenn ich MyModel.objects.first () starte, dauert es 5-10 Sekunden.
  2. Wenn ich ein einzelnes großes Dokument aus der Datenbank abfrage und dann auf sein Feld zugreife, dauert es nur 10-20 Sekunden, um Folgendes zu tun:

    %Vor%

Die Daten im Objekt enthalten keine Verweise auf andere Objekte, daher ist es kein Problem der Dereferenzierung von Objekten.
Ich vermute, dass es mit einer Ineffizienz der internen Datendarstellung von Mongoengine zusammenhängt, die sowohl die Konstruktion des Dokumentobjekts als auch den Zugriff auf Felder beeinflusst. Kann ich etwas tun, um das zu verbessern?

    
Baruch Oxman 07.02.2016, 18:24
quelle

1 Antwort

21

TL; DR: mongoengine veraltet sich und konvertiert alle zurückgegebenen Arrays in dicts

Um dies zu testen, habe ich eine Sammlung mit einem Dokument mit einem DictField mit einem großen verschachtelten dict erstellt. Das Dokument liegt ungefähr im Bereich von 5-10 MB.

Wir können dann timeit.timeit verwenden, um den Unterschied bei den Lesevorgängen mit Pymongo und Mongoengine zu bestätigen.

Wir können dann pycallgraph und GraphViz um zu sehen, was mongoengine so verdammt lange dauert.

Hier ist der vollständige Code:

%Vor%

Und die Ausgabe beweist, dass Mongoengine im Vergleich zu Pymongo sehr langsam ist:

%Vor%

Das resultierende Call-Diagramm zeigt ziemlich deutlich, wo der Flaschenhals ist:

Im Wesentlichen wird Mongoengine die Methode to_python für jedes DictField aufrufen, das es von der Datenbank zurückerhält. to_python ist ziemlich langsam und in unserem Beispiel wird es eine wahnsinnige Anzahl von Malen 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 eine etwas bessere Leistung von mongoengine zu erhalten. Ich habe einen ähnlichen, aber nicht äquivalenten Test Code in diesem Gist ausgeführt und die Ausgabe ist:

%Vor%

Damit kannst du Mongoengine schneller machen, aber Pymongo ist noch viel schneller.

AKTUALISIEREN

Eine gute Abkürzung zur Pymongo-Schnittstelle ist hier das Aggregation Framework:

%Vor%     
Steve Rossiter 08.02.2016, 16:52
quelle