Как сортировка с индексом работает в MongoDB?

мне интересно, как сортировка с индексом на самом деле работает в MongoDB. Есть пара статьи в документации MongoDB, но они фактически не описывают, как происходит сортировка или сложность времени. Поиски так и паутины в целом пока не выявили ничего существенного.

предположим, что есть a документы в коллекции, предложение find () соответствует b документы есть предел c документы возвращены, a >> b >> c и c - некоторое достаточно большое число, такое, что возвращаемый набор не может поместиться в память - скажем, 1M документов, например.

в начале операции, существуют b документы, которые должны быть отсортированы и отсортированы индекс дерева размера a функции документы будут отсортированы по.

I можете себе представить:

A) пересечь индекс по порядку, и для каждого ObjectID пересечь список b документы. Ответные матчи до c достигается. Это будет O (ab).

B) как A), но создайте хэш-набор объектов в b документы в первую очередь. Это O (a), но принимает O (b) памяти.

я попытался рассмотреть виды, основанные на прохождении набора b документы, но, похоже, не могут придумать ничего быстрее, чем O (b log b), что не лучше сортировки без индекса.

Я предполагаю (но, возможно, я ошибаюсь), что каждый вид не требует сканирования индекса, так как же на самом деле работает сортировка?

обновление:

ответ Кевина и предоставленная ссылка сильно сужают вопрос, но я хотел бы подтвердить / уточнить несколько очки:

  1. как я понимаю, вы не можете использовать разные индексы для запроса и сортировки, если хотите избежать сортировки в памяти. Когда я читаю на этой странице казалось, что вы можете (или, по крайней мере, не указали тот или иной способ), но это кажется неправильным. По сути, документы сортируются, потому что они просматриваются в порядке индекса во время запроса и поэтому возвращаются в порядке индекса. Правильно?
  2. при запросе составного индекса индекс сортировки должен быть первым индексом в составном индексе, за исключением индексов, где запрос-это равенство. Если нет, сортировка выполняется в памяти. Правильно?
  3. как сортировка работает с $in или $or запросы? Например, предположим, что запрос

    {a: {$in: [4, 6, 2, 1, 3, 10]}, b: {$gt: 1, $lt: 6}}

... и есть составной индекс на a и b в этом порядок. Как бы сортировка работала в случаях, когда сортировка включена a или b? $or еще сложнее, поскольку, как я понимаю,$or запросы по существу разделены на несколько отдельных запросов. Are $or запросы всегда сортируются в памяти, по крайней мере, для объединения результатов отдельных запросов?

1 ответов


индексы в MongoDB хранятся в структуре B-дерева, где каждая запись индекса указывает на определенное место на диске. Использование структуры B-дерева также означает, что индекс MongoDB хранится в отсортированном порядке, всегда проходит по порядку и дешев для MongoDB, чтобы получить серию документов в отсортированном порядке через индексы.

A SORT этап (т. е. сортировка в памяти) в запросе ограничен 32 МБ использования памяти. Запрос завершится ошибкой, если SORT этап превышает этот предел. Этот ограничение можно обойти, используя сортированный характер индексов, чтобы MongoDB мог возвращать запрос с sort() параметр без выполнения сортировки в памяти.

предположим, что запрос в виде:

    db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)

С a имея индекс:

    db.a.createIndex({b:1,c:1})

существует два возможных сценария, когда sort() этап указан в запросе:

1. MongoDB не может использовать сортированный характер index и должен выполнять in-memory SORT этап.

это результат, если запрос не может использовать "префикс индекса". Например:

    db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})

в приведенном выше запросе индекса {b:1,c:1} можно использовать в:

  • матч документов b более 100 за {b:{$gt:100}} часть запроса.
  • , нет никакой гарантии, что возвращенные документы сортируются по уровню c.

поэтому MongoDB не имеет выбора, кроме как выполнить сортировку в памяти. The explain() вывод этого запроса будет иметь SORT этап. Это SORT этап будет ограничен 32 МБ памяти.

2. MongoDB может использовать сортированный характер индекса.

это результат, если запрос использует:

  • сортировка ключей, соответствующих порядку индекса, и
  • указывает тот же порядок, что и индекс (т. е. индекс {b:1,c:1} может использоваться для sort({b:1,c:1}) или sort({b:-1,c:-1}) а не sort({b:1,c:-1}))

например:

    db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})

в приведенном выше запросе индекса {b:1,c:1} можно использовать в:

  • матч документов b более 100 за {b:{$gt:100}} часть запроса.
  • в этом случае MongoDB может гарантировать, что возвращенные документы отсортированы с точки зрения b.

на explain() вывод запроса выше будет не есть SORT этап. Кроме того,the explain() результат запроса с и без sort() одинаковые. По сути, мы получаем sort() бесплатно.

ценным ресурсом для понимания этой темы является Оптимизация Составных Индексов MongoDB. Обратите внимание, что это сообщение в блоге было написано еще в 2012 году. Хотя некоторые из терминология может быть устаревшей, техническая сторона должности по-прежнему актуальна.

Обновление ПО последующим вопросам

  1. MongoDB использует только один индекс для большинства запросов. Так, например, чтобы избежать in-memory SORT этап в запросе

    db.a.find({a:1}).sort({b:1})
    

    индекс должен охватывать как a и b поля одновременно; например, составной индекс, такой как {a:1,b:1} не требуется. У вас не может быть двух отдельные индексы {a:1} и {b:1}, и ожидать {a:1} индекс, который будет использоваться для части равенства, и {b:1} индекс, используемый для сортировки. В этом случае MongoDB выберет один из двух индексов.

    поэтому правильно, что результаты сортируются, потому что они просматриваются и возвращаются в порядке индекса.

  2. чтобы избежать сортировки в памяти с использованием составного индекса,первая часть индекса должны угодить части равенства запроса, и вторая часть должна обслуживать сортировочную часть запроса (как показано в объяснении для (1) выше).

    если у вас есть такой запрос:

    db.a.find({}).sort({a:1})
    

    индекс {a:1,b:1} может использоваться для части сортировки (так как вы в основном возвращаете всю коллекцию). И если ваш запрос выглядит так:

    db.a.find({a:1}).sort({b:1})
    

    один и тот же индекс {a:1,b:1} также может использоваться для обеих частей запроса. Также:

    db.a.find({a:1,b:1})
    

    можно также использовать тот же индекс {a:1,b:1}

    обратите внимание на шаблон здесь:find() следовал по sort() параметры следуют порядку индекса {a:1,b:1}. Поэтому составной индекс должен быть упорядочен по равенство -> сортировать.