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 так как используется только первое поле.

Другие вопросы по тегам