MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Mongoengine rất chậm trên các tài liệu lớn so với việc sử dụng pymongo bản địa

TL; DR:mongoengine đang dành nhiều thời gian để chuyển đổi tất cả các mảng được trả về thành các mảng

Để kiểm tra điều này, tôi đã tạo một bộ sưu tập với tài liệu có DictField với một dict lồng nhau lớn . Tài liệu nằm trong phạm vi 5-10MB của bạn.

Sau đó, chúng tôi có thể sử dụng timeit.timeit để xác nhận sự khác biệt về số lần đọc bằng cách sử dụng pymongo và mongoengine.

Sau đó, chúng tôi có thể sử dụng pycallgraph GraphViz để xem điều gì đang khiến mongoengine chết tiệt lâu như vậy.

Đây là mã đầy đủ:

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

Và kết quả đầu ra chứng tỏ mongoengine đang rất chậm so với pymongo:

pymongo took 0.87s
mongoengine took 25.81118331072267

Biểu đồ cuộc gọi kết quả minh họa khá rõ ràng cổ chai nằm ở đâu:

Về cơ bản mongoengine sẽ gọi phương thức to_python trên mọi DictField mà nó nhận được trở lại từ db. to_python khá chậm và trong ví dụ của chúng tôi, nó được gọi là một số lần điên rồ.

Mongoengine được sử dụng để ánh xạ cấu trúc tài liệu của bạn sang các đối tượng python một cách trang nhã. Nếu bạn có các tài liệu không có cấu trúc rất lớn (mongodb rất tuyệt vời) thì mongoengine không thực sự là công cụ phù hợp và bạn chỉ nên sử dụng pymongo.

Tuy nhiên, nếu bạn biết cấu trúc, bạn có thể sử dụng EmbeddedDocument để có được hiệu suất tốt hơn một chút từ mongoengine. Tôi đã chạy một bài kiểm tra tương tự nhưng không tương đương với mã trong ý chính này và đầu ra là:

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

Vì vậy, bạn có thể làm cho mongoengine nhanh hơn nhưng pymongo vẫn nhanh hơn nhiều.

CẬP NHẬT

Một lối tắt tốt cho giao diện pymongo ở đây là sử dụng khung tổng hợp:

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. Mongoose thêm nhiều mục vào cơ sở dữ liệu

  2. Cách truy vấn bộ sưu tập tài liệu con bằng MongoDB và trình điều khiển C #

  3. Không thể gắn các chia sẻ tệp azure dưới dạng khối lượng mongodb trong các trường hợp vùng chứa azure

  4. Mongoose TypeError:Không thể sử dụng toán tử 'in' để tìm kiếm '_id' trong [object Object]

  5. MongoSkin Không thể đọc thuộc tính 'apply' của undefined