Оптимизация составного индекса mongo для запроса с null, false и true

#mongodb

#mongodb

Вопрос:

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

 "query" : {
    "deleted_at" : null,
    "placed_at" : {
        "$exists" : true
    },
    "exported_at" : null,
    "failed_export" : false
}
  

В настоящее время просмотр таблицы занимает 2-3 минуты, даже если результатов нет. Объяснение показывает, что он просматривает сотни тысяч записей и не использует индекс.

Я попытался запустить это:

 db.some_table.createIndex({deleted_at: -1, placed_at: 1, exported_at: -1, failed_export: -1}, {background: true})
  

Когда я запускаю запрос позже:

 db.some_table.find({deleted_at: null, placed_at: {$exists: true}, exported_at: null, failed_export: false}).explain("executionStats")
  

Я вижу, что он использует правильный индекс, но он очень медленный. Он проверяет все 330494 строки. Вот статистика выполнения:

   "executionStats" : {
            "executionSuccess" : true,
            "nReturned" : 0,
            "executionTimeMillis" : 1585381,
            "totalKeysExamined" : 330494,
            "totalDocsExamined" : 330494,
            "executionStages" : {
                    "stage" : "FETCH",
                    "filter" : {
                            "$and" : [
                                    {
                                            "placed_at" : {
                                                    "$exists" : true
                                            }
                                    },
                                    {
                                            "deleted_at" : {
                                                    "$eq" : null
                                            }
                                    },
                                    {
                                            "exported_at" : {
                                                    "$eq" : null
                                            }
                                    },
                                    {
                                            "failed_export" : {
                                                    "$eq" : false
                                            }
                                    }
                            ]
                    },
  

Выигрышный план был:

            "winningPlan" : {
                    "stage" : "FETCH",
                    "filter" : {
                            "$and" : [
                                    {
                                            "placed_at" : {
                                                    "$exists" : true
                                            }
                                    },
                                    {
                                            "deleted_at" : {
                                                    "$eq" : null
                                            }
                                    },
                                    {
                                            "exported_at" : {
                                                    "$eq" : null
                                            }
                                    },
                                    {
                                            "failed_export" : {
                                                    "$eq" : false
                                            }
                                    }
                            ]
                    },
                    "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                    "placed_at" : 1
                            },
                            "indexName" : "placed_at_1",
                            "isMultiKey" : false,
                            "direction" : "forward",
                            "indexBounds" : {
                                    "placed_at" : [
                                            "[MinKey, MaxKey]"
                                    ]
                            }
                    }
            },
  

И в нем был указан индекс, который я создал в одном из отклоненных планов.

Есть идеи о том, почему он будет проходить через каждую запись в базе данных? Это снижает нашу производительность.

Я пытался указать правильную запись, и это, похоже, не очень помогло.

Ответ №1:

Вместо запроса deleted_at: null было бы лучше создать новое status поле или isDeleted поле и настроить серверы приложений для заполнения этого поля. Затем вы можете создать более эффективный индекс для этого поля, чтобы найти все ваши документы, удаленные программным путем.

Из рекомендаций по производительности для технического документа MongoDB:

Избегайте отрицания в запросах.Как и большинство систем баз данных, MongoDB не индексирует отсутствие значений, и условия отрицания могут потребовать сканирования всех документов. Если отрицание является единственным условием и оно не является выборочным (например, запрос таблицы заказов, где 99% заказов выполнены, чтобы идентифицировать те, которые не были выполнены), все записи необходимо будет отсканировать.