//FAST
db.datasources.find().count()
12036788
//SLOW
db.datasources.find({nid:19882}).count()
10161684
Индекс по ниду
Как сделать второй запрос быстрее? (Это занимает около 8 секунд)
//FAST
db.datasources.find().count()
12036788
//SLOW
db.datasources.find({nid:19882}).count()
10161684
Индекс по ниду
Как сделать второй запрос быстрее? (Это занимает около 8 секунд)
Количество запросов, индексированных или иным образом, происходит медленно из-за того, что MongoDB все еще должен выполнить полную b-tree walk, чтобы найти соответствующее количество документов, соответствующих вашим критериям. Причиной этого является то, что структура b-tree MongoDB не "подсчитывается", так как каждый node не хранит информацию о количестве элементов в node/поддереве.
Проблема приведена здесь https://jira.mongodb.org/browse/SERVER-1752, и в настоящее время нет обходного пути для повышения производительности, кроме ручного ведения счетчика для этой коллекции, который, очевидно, поставляется с несколькими минусами.
Также обратите внимание, что версия db.col.count() (так что нет критериев) может иметь большой ярлык и фактически не выполняет запрос, следовательно, скорость. При этом он не всегда сообщает о том же значении, что и запрос счетчика, который должен возвращать все элементы (например, он не будет в оштукатуренных средах с высокой пропускной способностью записи). Подумайте о том, есть ли эта ошибка. Я думаю, что это так.
Обратите внимание, что в версии 2.3+ была введена значительная оптимизация, которая должна (и делает) улучшать производительность подсчетов по индексированным полям. См.: https://jira.mongodb.org/browse/SERVER-7745
Как сказал @Remon, count() должен отсканировать все документы, соответствующие запросу/фильтру. Это O (n), где n - количество документов, которые будут соответствовать индексу, или количество документов в коллекции, если поле не индексировано.
В таких случаях вы, как правило, хотите пересмотреть свое требование. Вам действительно нужно точное число для результата 10161684? Если точность важна, вы должны сохранить отдельный счетчик для конкретного запроса.
Но в большинстве случаев точность не важна. Это один из двух:
В моих приложениях я обнаружил, что второй вариант - это то, что я хочу. Таким образом, я также ограничиваю запрос count(), так что подсчет останавливается, когда он достигает предела. Например:
db.datasources.find({nid: 19882}).limit(1000).count(true)
Для пользователя я показываю "1000 или более найденных результатов", если число равно 1000, в противном случае я показываю точный номер.
Что касается первого варианта... Я еще не думал о аккуратном решении.
Он должен просматривать каждое поле каждого документа для второго. Вы можете индексировать nid
, чтобы сделать счет быстрее.