“文档” 菜单
文档首页
/
MongoDB Manual
/ /

多键索引

在此页面上

  • 用例
  • 开始体验
  • 详情
  • 索引边界
  • 唯一多键索引
  • 复合多键索引
  • 排序
  • 分片键
  • 哈希(Hashed)索引
  • 覆盖查询
  • 对数组字段进行整体查询
  • $expr
  • 了解详情

多键索引从包含数组值的字段中收集数据并进行排序。多键索引可提高对数组字段的查询性能。

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

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

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

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

下图显示了 addr.zip 字段的多键索引:

针对“addr.zip”的多键索引图示字段。“addr”字段包含地址文档的数组。地址文档包含“zip”字段。

对于 MongoDB Atlas 中托管的部署,您可以 在用户界面中创建和管理多键索引

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

对经常查询的字段进行索引可以增加覆盖这些查询的机会。覆盖查询是可以完全使用索引来满足的查询,而无需检查任何文档。这样可以优化查询性能。

例如,students 集合中的文档包含 test_scores 字段:学生在整个学期中收到的测验成绩的数组。您会定期更新排名靠前学生的列表:至少有五项 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 集合在 nameevent 字段上具有复合多键索引:

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

此索引为多键索引,因为 event 字段包含数组值。

多键索引涵盖以下查询,即使匹配字段 (name) 不是数组:

db.matches.find( { name: "bill" } )

由于 name 字段是索引前缀的一部分,因此索引涵盖了对 name 字段的查询。该索引无法同时涵盖对 nameevent 的查询,因为多键索引无法涵盖对数组字段的查询。

当查询过滤器指定了与整个数组完全匹配的匹配项时,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 ] }
] )

inventory 集合在 ratings 字段上有一个多键索引:

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

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

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

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

$expr 操作符不支持多键索引。

← 复合索引排序顺序