MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Mongoengine sangat lambat pada dokumen besar dibandingkan dengan penggunaan pymongo asli

TL;DR:mongoengine menghabiskan waktu lama untuk mengubah semua array yang dikembalikan menjadi dicts

Untuk mengujinya, saya membuat koleksi dengan dokumen dengan DictField dengan dict bersarang besar . Dokumen kira-kira dalam kisaran 5-10MB Anda.

Kami kemudian dapat menggunakan timeit.timeit untuk mengonfirmasi perbedaan pembacaan menggunakan pymongo dan mongoengine.

Kami kemudian dapat menggunakan pycallgraph dan GraphViz untuk melihat apa yang membuat mongoengine begitu lama.

Berikut kode lengkapnya:

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()

Dan hasilnya membuktikan bahwa mongoengine sangat lambat dibandingkan dengan pymongo:

pymongo took 0.87s
mongoengine took 25.81118331072267

Grafik panggilan yang dihasilkan menggambarkan dengan cukup jelas di mana letak leher botol:

Pada dasarnya mongoengine akan memanggil metode to_python pada setiap DictField bahwa itu akan kembali dari db. to_python cukup lambat dan dalam contoh kami itu disebut gila berkali-kali.

Mongoengine digunakan untuk memetakan struktur dokumen Anda secara elegan ke objek python. Jika Anda memiliki dokumen tidak terstruktur yang sangat besar (yang sangat bagus untuk mongodb) maka mongoengine bukanlah alat yang tepat dan Anda sebaiknya menggunakan pymongo.

Namun, jika Anda mengetahui strukturnya, Anda dapat menggunakan EmbeddedDocument bidang untuk mendapatkan kinerja yang sedikit lebih baik dari mongoengine. Saya telah menjalankan kode dalam inti ini yang serupa tetapi tidak setara dan hasilnya adalah:

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

Jadi Anda dapat membuat mongoengine lebih cepat tetapi pymongo masih jauh lebih cepat.

PERBARUI

Jalan pintas yang baik untuk antarmuka pymongo di sini adalah dengan menggunakan kerangka kerja agregasi:

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



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. fungsi Azure (simpul) memanggil mongodb selesai tanpa kesalahan tetapi tidak ada yang kembali dari kueri

  2. Menggunakan $push dalam Array di luwak

  3. (Sudut 2) Cara mengisi dropdown berdasarkan pilihan dropdown lain

  4. Masalah dalam mengembalikan data yang diambil dari kueri DB yang disebut dalam loop

  5. Manual Audit Database Sumber Terbuka DevOps - Semua Yang Harus Anda Ketahui