MongoDB не использует мой индекс
У меня есть коллекция журналов с миллионами записей. Создание нового индекса занимает "навсегда". Поэтому было бы предпочтительнее использовать существующие индексы.
Теперь я хочу получить количество вхождений определенных кодов ошибок. Я использую этот запрос, и функционально он работает нормально:
db.getCollection('logs.res').aggregate([
{
$match:{
timeStamp: {
$gte: new Date('2017-05-01').getTime(), // timeStamp is Number
$lt : new Date('2017-05-02').getTime() // of ms since epoch
},
'objData.@.ErrorCode': {
$ne: null
}
}
},
{
$group: {
_id: '$objData.@.ErrorCode',
count: {$sum: 1}
}
},
{
$sort: { count: -1}
}
]);
Проблема в том, что для выполнения этого в течение дня требуется около 10 секунд. Я предполагал, что будет использован следующий индекс: timeStamp_-1_objData.@.ErrorCode_1
:
{
"timeStamp" : -1,
"objData.@.ErrorCode" : 1
}
Тем не менее, MongoDB кажется непреклонным использовать некоторые timeStamp: 1
индекс (с некоторыми другими индексами, не связанными с запросом), и просканируйте все результаты, чтобы увидеть, могут ли некоторые ответы иметь ErrorCode
прилагается, хотя эта информация должна быть в индексе.
Здесь explain()
:
- Есть ли способ использовать
timeStamp_-1_objData.@.ErrorCode_1
Индекс, чтобы ускорить это? - Почему он не использует этот индекс? Я, вероятно, неправильно понимаю, как индексы используются в этом запросе.
Запуск MongoDB 3.2.7 на OSX.
примечание: я тоже пробовал $empty: true
вместо $ne: null
, Это дает те же результаты, но некоторые говорят, что вы не можете использовать $empty
если вы хотите использовать составной индекс. Однако многие вопросы по переполнению стека устарели (mongo 2.x).
2 ответа
План выигрыша CACHED PLAN
, Вы можете попробовать очистить план кеша.
db.getCollection('logs.res').getPlanCache().clear()
Если после очистки кеша Mongo все еще использует неверный индекс. Вы можете попытаться установить план запроса или использовать "подсказку" для принудительного индексирования
Обычные индексы mongodb используют как значение поля, так и тип для построения дерева.
Запросы как $empty: true
или же $ne: null
не имеет параметров любого типа и не может извлечь выгоду из таких индексов. Это особый случай и требует особого разреженного индекса.
Если твой timeStamp_-1_objData.@.ErrorCode_1
Индекс создается как:
db.getCollection('logs.res').createIndex(
{
"timeStamp" : -1,
"objData.@.ErrorCode" : 1
},
{ sparse: true }
)
Это должно поддержать ваш запрос лучше всего. В противном случае нет большой разницы между timeStamp_-1_objData.@.ErrorCode_1
а также timeStamp_1_module_1_etc
так как используется только первое поле.