Индекс Mongodb, следует ли включать в индекс частичные фильтры? - PullRequest
0 голосов
/ 27 марта 2020

У меня такой запрос:

collection.find({
  type: "person",
  image: {
    $exists: true
  }
}, {
  sort: [
    ["age", -1]
  ],
  limit: 9,
)

Нужно ли включать поля в индекс, если я их уже отфильтровал?

collection.createIndex(
  {type: 1, image: 1, age: -1}, 
  { 
    partialFilterExpression: {
      type: 'person',
      image: {
        $exists: true
      }
    },
    background: true
  }
)

Или он уже знает выражением частичного фильтра, а я запрашиваю только то, что не исправлено?

collection.createIndex(
  {age: -1}, 
  { 
    partialFilterExpression: {
      type: 'person',
      image: {
        $exists: true
      }
    },
    background: true,
    name: "ageIndex"
  }
)

Подумайте об этом, возможно, правильнее всего сделать не индексировать все поля, а использовать подсказку, чтобы заставить БД использовать индекс?

collection.find({
  type: "person",
  image: {
    $exists: true
  }
}, {
  sort: [
    ["age", -1]
  ],
  limit: 9,
).hint("ageIndex")

Будет ли это правильно использовать индекс и игнорировать другие документы в коллекции?

Ответы [ 2 ]

0 голосов
/ 30 марта 2020

Рассмотрим коллекцию образцов документов , которые запрашиваются, как в вопросе:

{ _id: 1, type: "person", image: "i-1", age: 19, "fld": 12 },
{ _id: 2, type: "person", image: "i-2", age: 22, "fld": 121 },
{ _id: 3, type: "thing", image: "i-99", age: 29, "fld": 1212 },    // 'type' not 'person'
{ _id: 4, type: "person", age: 31, "fld": 12121 },                 // 'image' missing
{ _id: 5, type: "person", image: "i-3", age: 13, "fld": 121212 },
{ _id: 6, type: "person", age: 43, "fld": 1212121 },               // 'image' missing
{ _id: 7, type: "person", image: "i-4", age: 20, "fld": 1 }

Нужно ли включать поля в индекс, если они у меня уже есть? фильтруется? Или это уже известно по выражению частичного фильтра, а я запрашиваю только то, что не исправлено?

Создать index :

db.collection.createIndex( { type: 1, age: -1 },
  {
     partialFilterExpression: {
       type: 'person',
       image: { $exists: true }
    }
  }
)

Примечание поля индекса только на type и age. Почему? Это объясняется в проверке использования индекса ниже.

запрос :

db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } )

Результат :

Запрос возвращает ожидаемые отфильтрованные документы и в отсортированном порядке.

{ "_id" : 2, "type" : "person", "image" : "i-2", "age" : 22, "fld" : 121 }
{ "_id" : 7, "type" : "person", "image" : "i-4", "age" : 20, "fld" : 1 }
{ "_id" : 1, "type" : "person", "image" : "i-1", "age" : 19, "fld" : 12 }
{ "_id" : 5, "type" : "person", "image" : "i-3", "age" : 13, "fld" : 121212 }


Проверка использования индекса:

Использование индекса можно проверить, сгенерировав план запроса с использованием explain Метод:

db.collection.find( { type: "person", image: { $exists: true } } ).sort( { age: -1 } ).explain()

Выходные данные плана показывают использование индекса для операций сортировки фильтра и . Это отмечается как IXSCAN (индексированное сканирование) и отсутствие этапа SORT в плане. Это правильное использование индекса для этого запроса.

В определении индекса два поля type + age задают составной индекс. Для этого требуется, чтобы индекс применялся к type (для фильтрации) и age (для сортировки). Поле image нельзя указать в определении индекса, так как оно не используется с условием равенства (использует $exists); если указано, индекс не будет использоваться для следующего отсортированного поля (из документации ):

Индекс может поддерживать операции сортировки в подмножестве без префикса ключа индекса шаблон. Для этого запрос должен включать условия равенства для всех префиксных ключей, предшествующих ключам сортировки.

План запроса (часть его):

{
    "queryPlanner" : {
            "plannerVersion" : 1,
            "namespace" : "test.persons",
            "indexFilterSet" : false,
            "parsedQuery" : {
                    "$and" : [
                            {
                                    "type" : {
                                            "$eq" : "person"
                                    }
                            },
                            {
                                    "image" : {
                                            "$exists" : true
                                    }
                            }
                    ]
            },
            "queryHash" : "25E877F5",
            "planCacheKey" : "C9D745BE",
            "winningPlan" : {
                    "stage" : "FETCH",
                    "filter" : {
                            "image" : {
                                    "$exists" : true
                            }
                    },
                    "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                    "type" : 1,
                                    "age" : -1
                            },
                            "indexName" : "type_1_age_-1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                    "type" : [ ],
                                    "age" : [ ]
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : true,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                    "type" : [
                                            "[\"person\", \"person\"]"
                                    ],
                                    "age" : [
                                            "[MaxKey, MinKey]"
                                    ]
                            }
                    }
            }, ...
0 голосов
/ 30 марта 2020

В соответствии с документацией Partial Index MongoDB нет необходимости включать поля в индекс, если они уже находятся в partalFilterExpression, если выполняется запрос в этом выражении.

Указанный ниже индекс будет отлично работает для предоставленного запроса.

collection.createIndex(
  {age: -1}, 
  {partialFilterExpression: { type: 'person', image: { $exists: true }}}
)

Запрос:

collection.find({type: "person", image: { $exists: true }}, {sort: [["age", -1]])

Даже подсказка не требуется.

Важно : если тип не будет «персона», или фильтр для изображения не будет предоставлен - индекс не будет работать.

Индекс будет работать ТОЛЬКО , если результат запрос 100% в индексе.

Другой пример из документации:

Индекс:

db.restaurants.createIndex(
   { cuisine: 1, name: 1 },
   { partialFilterExpression: { rating: { $gt: 5 } } }
)

Запрос:

db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )

Этот запрос будет не подпадают под вышеуказанный индекс по причине, что он включает рейтинг ниже 5.

...