文档菜单
文档首页
/
MongoDB 手册
/ /

多键索引

本页

  • 用例
  • 入门
  • 详细信息
  • 索引范围
  • 唯一多键索引
  • 复合多键索引
  • 排序
  • 分片键
  • 哈希索引
  • 覆盖查询
  • 作为整体查询数组字段
  • $expr
  • 了解更多

多键索引收集并排序包含数组值的字段的数椐。多键索引提高了对数组字段的查询性能。

您不需要显式指定多键类型。当您在包含数组值的字段上创建索引时,MongoDB会自动将该索引设置为多键索引。

MongoDB可以为包含标量值(例如,字符串和数字)和嵌套文档的数组创建多键索引。如果一个数组包含相同值的多个实例,则索引只为该值包含一个条目。

要创建多键索引,请使用以下原型

db.<collection>.createIndex( { <arrayField>: <sortOrder> } )

此图像显示了在addr.zip 字段上的多键索引

Diagram of a multikey index on the ``addr.zip`` field. The ``addr`` field contains an array of address documents. The address documents contain the ``zip`` field.

您可以在 在MongoDB Atlas中创建和管理多键索引的UI 上托管的应用程序中

如果您的应用程序经常查询包含数组值的字段,则多键索引可以提高这些查询的性能。

索引常用查询字段可以增加覆盖

这些查询的机会。覆盖查询是可以完全使用索引满足的查询,无需检查任何文档。这优化了查询性能。

例如,一个名为 students 的集合中的文档包含一个 test_scores 字段:一个学生在整个学期内获得的测试分数数组。您经常更新一个顶级学生的列表:至少有五个测试分数超过 90 的学生。

您可以在 test_scores 字段上创建索引,以提升此查询的性能。因为 test_scores 包含数组值,MongoDB 将索引存储为多键索引。

要创建多键索引,请参阅

本节描述了多键索引的技术细节和限制。

索引扫描的边界定义了在查询过程中搜索索引的部分。多键索引边界的计算遵循特殊规则。有关详细信息,请参阅 多键索引边界。

在一个 唯一 多键索引中,一个文档可能具有导致重复索引键值的数组元素,只要该文档的索引键值不重复另一个文档的索引键值。

要了解更多信息并查看此行为的示例,请参阅 不同文档中的唯一约束。

在一个 复合 多键索引中,每个索引文档可以有一个 最多 的索引字段其值是一个数组。具体来说

  • 如果索引规范中超过一个字段是数组,则无法创建复合多键索引。例如,考虑包含以下文档的集合

    { _id: 1, scores_spring: [ 8, 6 ], scores_fall: [ 5, 9 ] }

    无法创建复合多键索引 { scores_spring: 1, scores_fall: 1 },因为索引中的两个字段都是数组。

  • 如果已经存在复合多键索引,则无法插入违反此限制的文档。

    考虑包含以下文档的集合

    { _id: 1, scores_spring: [8, 6], scores_fall: 9 }
    { _id: 2, scores_spring: 6, scores_fall: [5, 7] }

    可以创建复合多键索引 { scores_spring: 1, scores_fall: 1 },因为对于每个文档,复合多键索引中只索引了一个字段是数组。没有任何文档同时包含 scores_springscores_fall 字段的数组值。

    然而,在创建复合多键索引后,如果尝试插入同时包含 scores_springscores_fall 字段为数组的文档,则插入失败。

当你根据一个使用多键索引索引的数组字段进行排序时,除非以下两个条件都满足,否则查询计划将包括一个阻塞排序阶段:

  • 所有排序字段的索引边界都是[MinKey, MaxKey]

  • 没有任何多键索引字段的边界与排序模式具有相同的路径前缀。

你不能将多键索引指定为分片键索引。

然而,如果分片键索引是一个前缀复合索引,那么如果其中一个后续键(不是分片键的一部分)索引一个数组,复合索引可能成为一个复合多键索引。

哈希索引不能是多键索引。

当满足以下条件时,多键索引可以覆盖查询

例如,考虑一个包含以下文档的matches集合

db.matches.insertMany( [
{ name: "Joe", event: [ "open", "tournament" ] },
{ name: "Bill", event: [ "match", "championship" ] }
] )

matches集合在eventname字段上有一个组合多键索引

db.matches.createIndex( { event: 1, name: 1 } )

前面的索引是多键索引,因为event字段包含数组值。

此索引覆盖以下查询

db.matches.find(
{ event: 'championship' },
{ _id: 0, name: 1 }
)
db.matches.find(
{ name: 'Bill', event: 'championship' },
{ _id: 0, name: 1 }
)

由于投影包含event数组字段,该索引不覆盖以下查询

db.matches.find(
{ event: 'championship' },
{ _id: 0, event: 1 }
)

当查询过滤器指定一个整个数组的精确匹配时,MongoDB可以使用多键索引查找查询数组中的第一个元素,但不能使用多键索引扫描来找到整个数组。

相反,在MongoDB使用多键索引查找查询数组的第一个元素之后,它检索相关的文档并过滤出数组与查询中的数组匹配的文档。

例如,考虑一个包含以下文档的inventory集合

db.inventory.insertMany( [
{ _id: 5, type: "food", item: "apple", ratings: [ 5, 8, 9 ] }
{ _id: 6, type: "food", item: "banana", ratings: [ 5, 9 ] }
{ _id: 7, type: "food", item: "chocolate", ratings: [ 9, 5, 8 ] }
{ _id: 8, type: "food", item: "fish", ratings: [ 9, 5 ] }
{ _id: 9, type: "food", item: "grapes", ratings: [ 5, 9, 5 ] }
] )

库存集合在ratings字段上有一个多键索引。

db.inventory.createIndex( { ratings: 1 } )

以下查询寻找ratings字段为数组[ 5, 9 ]的文档。

db.inventory.find( { ratings: [ 5, 9 ] } )

MongoDB可以使用多键索引来查找数组中任何位置包含5的文档。然后,MongoDB检索这些文档,并筛选出数组ratings等于查询数组[ 5, 9 ]的文档。

$expr运算符不支持多键索引。

返回

排序顺序