Что в действительности означает индексирование ключа внедренного документа?

Я до сих пор не могу понять, как на самом деле работает индексирование ключа внедренного документа.
Предположим, у меня есть следующая коллекция сообщений в блоге:

{
    _id:0,
    author: 'John Doe',
    content: 'How indexing an embedded document work?',
    comments:
    [
      {
        sender:'Jane Doe',
        content: 'I can\'t make it out either.'
      },
      etc...
    ]
},
etc...

Предположим, теперь я установил индекс для свойства отправителя в комментариях:

db.blog.createIndex({'comments.sender':1})

Теперь вопрос:
Означает ли это, что большой индекс создается для всех элементов, упорядоченных отправителем в порядке возрастания, независимо от того, в каком массиве они находятся? Или индекс создается для каждого массива?
Чтобы было понятнее: когда я

blog.find({'comments.sender':'Jane Doe'}).toArray(function(err, array){})

Будет ли он проходить через каждое сообщение в блоге и искать каждый массив, пока в этом массиве не будет найдена запись, и перейти к следующему массиву в следующем сообщении? Или существует большой индекс, в котором каждая запись (упорядоченная отправителем) сопоставляется с исходным массивом, в котором находится это совпадение?

1 ответ

Решение

Это создает индекс с одной записью на комментарий. Если у вас есть 2 сообщения в блоге с 3 комментариями, у вас будет индекс с 6 записями, проиндексированный по имени отправителя комментария. Ваша вторая гипотеза верна: ваш поиск найдет все комментарии с правильным отправителем, эффективно используя этот индекс, а затем вернет соответствующие сообщения в блоге.

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

Вы можете легко проверить сложность ваших запросов с помощью объяснения:

> db.blog.insert({'comments': [{'sender': 'Jane'}]})
WriteResult({ "nInserted" : 1 })
> db.blog.insert({'comments': [{'sender': 'Jane'}, {'sender': 'Joe'}]})
WriteResult({ "nInserted" : 1 })
> db.blog.insert({'comments': [{'sender': 'Joe'}]})
WriteResult({ "nInserted" : 1 })
> db.blog.ensureIndex({'comments.sender': 1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.blog.find({'comments.sender': 'Jane'}).count()
2
> db.blog.find({'comments.sender': 'Jane'}).explain()
{
        "cursor" : "BtreeCursor comments.sender_1",
        "isMultiKey" : true,
        "n" : 2,
        "nscannedObjects" : 2,
        "nscanned" : 2,
        "nscannedObjectsAllPlans" : 2,
        "nscannedAllPlans" : 2,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
                "comments.sender" : [
                        [
                                "Jane",
                                "Jane"
                        ]
                ]
        },
        "server" : "metrics.9.0.api.production.infinit.io:27017",
        "filterSet" : false
}

Здесь мы видим, что индекс действительно использовался ("BtreeCursor") и что было проверено только 2 объекта, а не все 3. Удалите индекс, и вы получите сканирование таблицы:

> db.blog.dropIndex({'comments.sender': 1})
{ "nIndexesWas" : 2, "ok" : 1 }
> db.blog.find({'comments.sender': 'Jane'}).explain()
{
        "cursor" : "BasicCursor",
        "isMultiKey" : false,
        "n" : 2,
        "nscannedObjects" : 3,
        "nscanned" : 3,
        "nscannedObjectsAllPlans" : 3,
        "nscannedAllPlans" : 3,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "server" : "metrics.9.0.api.production.infinit.io:27017",
        "filterSet" : false
}
Другие вопросы по тегам