Как сортировка с индексом работает в 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), что не лучше сортировки без индекса.
Я предполагаю (но, возможно, я ошибаюсь), что каждый вид не требует сканирования индекса, так как же на самом деле работает сортировка?
обновление:
ответ Кевина и предоставленная ссылка сильно сужают вопрос, но я хотел бы подтвердить / уточнить несколько очки:
- как я понимаю, вы не можете использовать разные индексы для запроса и сортировки, если хотите избежать сортировки в памяти. Когда я читаю на этой странице казалось, что вы можете (или, по крайней мере, не указали тот или иной способ), но это кажется неправильным. По сути, документы сортируются, потому что они просматриваются в порядке индекса во время запроса и поэтому возвращаются в порядке индекса. Правильно?
- при запросе составного индекса индекс сортировки должен быть первым индексом в составном индексе, за исключением индексов, где запрос-это равенство. Если нет, сортировка выполняется в памяти. Правильно?
-
как сортировка работает с
$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 году. Хотя некоторые из терминология может быть устаревшей, техническая сторона должности по-прежнему актуальна.
Обновление ПО последующим вопросам
-
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 выберет один из двух индексов.поэтому правильно, что результаты сортируются, потому что они просматриваются и возвращаются в порядке индекса.
-
чтобы избежать сортировки в памяти с использованием составного индекса,первая часть индекса должны угодить части равенства запроса, и вторая часть должна обслуживать сортировочную часть запроса (как показано в объяснении для (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}
. Поэтому составной индекс должен быть упорядочен по равенство -> сортировать.