TL; DRは:mongoengineはこれをテストするにはdicts
にすべて返された配列を変換年齢を費やしている私は、大規模なネストされたdict
とDictField
と文書のコレクションを構築しました。ドキュメントはおよそ5-10MBの範囲にあります。
次に、timeit.timeit
を使用して、pymongoとmongoengineを使用して読み込みの違いを確認できます。
次に、私はpycallgraphとGraphVizを使用して、何がmongoengineをしているのか見てみましょう。ここで
がいっぱいのコードです:
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()
、出力はmongoengineがpymongoに比べて非常に遅い中であることを証明している:
pymongo took 0.87s
mongoengine took 25.81118331072267
結果、コールグラフはかなり明確にどこボトルネックを示しています次のとおりです。
基本的にmongoengineはdbから戻ってくるすべてのDictField
に対してto_pythonメソッドを呼び出します。 to_python
はかなり遅く、私たちの例ではそれは非常識な回数と呼ばれています。
Mongoengineは、ドキュメント構造をPythonオブジェクトにエレガントにマッピングするために使用されます。非常に大きな非構造化文書(mongodbは素晴らしい)があれば、mongoengineは本当に適切なツールではなく、pymongoを使用するだけです。
しかし、あなたが構造を知っていれば、EmbeddedDocument
フィールドを使用してmongoengineから少し良いパフォーマンスを得ることができます。私は同等ではないが類似の試験code in this gistを実行したと出力は次のようになりますので、あなたがより速くmongoengineを作ることができます
pymongo with dict took 0.12s
pymongo with embed took 0.12s
mongoengine with dict took 4.3059175412661075
mongoengine with embed took 1.1639373211854682
が、まだはるかに高速pymongoです。
UPDATE
ここpymongoインターフェイスへの良好なショートカットが集約フレームワークを使用することです:
def mongoengine_agg_doc():
return list(MyModel.objects.aggregate({"$limit":1}))[0]
2つの異なるものがあるようです。ネイティブメソッドは1つのドキュメントをロードして停止し、mongoengineはすべてのドキュメントをロードして最初のドキュメントを返します。 'find_one()'から 'list(db.collection.find())[0]'に変更してメソッドと等しくするようにしてください。 – Valijon
また、mongoengineクエリでlimit(1)を追加しようとしましたが、それは役に立ちませんでした。ほとんどの時間は、すべてのネストされたオブジェクトを持つmongoengine Documentオブジェクトの構築に費やされていると思われます。 –
ドキュメントが読み込まれると 'skip'と' limit'が動作します: /docs.mongoengine.org/guide/querying.html#query-operators](http://docs.mongoengine.org/guide/querying.html#query-operators) – Valijon