MongoDB Агрегация с $sample очень медленная

Существует множество способов выбора случайного документа из коллекции mongodb (как обсуждалось в этом ответе). Комментарии указывают, что с версией mongodb >= 3.2, тогда использование $sample в структуре агрегации является предпочтительным. Однако в коллекции со многими небольшими документами это кажется чрезвычайно медленным.

В следующем коде используется mongoengine для имитации проблемы и сравнения ее с методом "skip random":

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 работает так медленно.

Я что-то упустил? Что это за пример, который вызывает агрегацию так долго?

Ответ 2

Я могу подтвердить, что ничего не изменилось в 3.6 Проблема Slow $sample сохраняется. Позор вам, команда MongoDB.

~ 40 м коллекция небольших документов, без индексов, Windows Server 2012 x64.

хранения:   wiredTiger.engineConfig.journalCompressor: zlib   wiredTiger.collectionConfig.blockCompressor: zlib

2018-04-02T02: 27: 27.743-0700 Команда COMMAND [conn4] maps.places

команда: aggregate {aggregate: "places", конвейер: [{$ sample: {size: 10}}],

 cursor: {}, lsid: { id: UUID("0e846097-eecd-40bb-b47c-d77f1484dd7e") }, $readPreference: { mode: "secondaryPreferred" }, $db: "maps" } planSummary: MULTI_ITERATOR keysExamined:0 docsExamined:0 cursorExhausted:1 numYields:3967 nreturned:10 reslen:550 locks:{ Global: { acquireCount: { r: 7942 } }, Database: { acquireCount: { r: 3971 } }, Collection: { acquireCount: { r: 3971 } } }

: op_query 72609ms

Я установил Mongo, чтобы попробовать эту "современную и совершенную СУБД" в серьезном проекте. Как глубоко я расстроен.

Объяснить план можно здесь:

db.command('aggregate', 'places', pipeline=[{"$sample":{"size":10}}], explain=True)

 {'ok': 1.0,
  'stages': [{'$cursor': {'query': {},
    'queryPlanner': {'indexFilterSet': False,
     'namespace': 'maps.places',
     'plannerVersion': 1,
     'rejectedPlans': [],
     'winningPlan': {'stage': 'MULTI_ITERATOR'}}}},
  {'$sampleFromRandomCursor': {'size': 10}}]}