Существует множество способов выбора случайного документа из коллекции mongodb (как обсуждалось in this answer). Комментарии указывают, что с версией mongodb> = 3.2, тогда использование $sample
в структуре агрегации является предпочтительным. Однако в коллекции со многими небольшими документами это кажется чрезвычайно медленным.
Следующий код использует mongoengine для имитации проблемы и сравнить его с «перескочить» случайного метода:
import timeit
from random import randint
import mongoengine as mdb
mdb.connect("test-agg")
class ACollection(mdb.Document):
name = mdb.StringField(unique=True)
meta = {'indexes': ['name']}
ACollection.drop_collection()
ACollection.objects.insert([ACollection(name="Document {}".format(n)) for n in range(50000)])
def agg():
doc = list(ACollection.objects.aggregate({"$sample": {'size': 1}}))[0]
print(doc['name'])
def skip_random():
n = ACollection.objects.count()
doc = ACollection.objects.skip(randint(1, n)).limit(1)[0]
print(doc['name'])
if __name__ == '__main__':
print("agg took {:2.2f}s".format(timeit.timeit(agg, number=1)))
print("skip_random took {:2.2f}s".format(timeit.timeit(skip_random, number=1)))
Результат является:
Document 44551
agg took 21.89s
Document 25800
skip_random took 0.01s
Где бы я имел проблемы с производительностью mongodb в прошлом, мой ответ всегда заключался в использовании структуры агрегации, поэтому я удивлен $sample
настолько медленный.
Я что-то упустил? Что это за пример, который вызывает агрегацию так долго?
Какая версия MongoDB работает? Я обнаружил, что '$ sample' был очень медленным в 3.2.5, но в основном мгновенным в 3.2.7. – JohnnyHK
ах, 3.2.0 - тогда это будет. да, [это] (https://jira.mongodb.org/browse/SERVER-21887?jql=text%20~%20%22%24sample%22) показывает, что это была известная ошибка. –
Правильно, но я не уверен, почему для меня все еще было медленным с 3.2.5 с новой коллекцией документов 1М, как это было отмечено в 3.2.3. – JohnnyHK