【MongoDB】多键索引(Multikey Indexes)

本章内容:

  • 创建多键索引
  • 指标界限
  • 唯一多键索引
  • 局限性
  • 例子

如果一个字段的保存值是数组,那么,为该字段创建索引时,MongoDB为数组中的每个元素创建一个索引键。这些多键索引支持对数组字段的有效查询。可以在数组上构造多键索引,数组中既可以保存标量值[1](例如字符串,数字)也可以是嵌套文档。

addr.zip字段上的多键索引图。addr字段包含一个地址文档数组。地址文档包含”zip”字段。

 

[1]标量值是指既不是嵌入式文档也不是数组的值。

一、创建多键索引

要创建多键索引,请使用db.collection.createIndex()方法:

db.coll.createIndex( { <field>: < 1 or -1 > } )

如果一个索引字段是数组,MongoDB会自动创建一个多键索引;而无需显式指定多键类型。

在版本3.4中的更改:仅对于WiredTigerIn-Memory存储引擎

从MongoDB 3.4开始,对于使用MongoDB 3.4或更高版本创建的多键索引,MongoDB会跟踪创建了多键索引的一个或多个字段。跟踪此信息使MongoDB查询引擎可以使用更严格的索引范围。

 

二、索引边界

如果索引是多键,则索引边界的计算需遵循特殊规则。有关多键索引范围的详细信息,请参见多键索引边界

 

三、唯一多键索引

对于唯一索引,唯一性约束作用跨越了集合中的多个独立文档,而不是单个文档。

因为唯一性约束适用于单独的文档,所以对于唯一的多键索引,文档可能具有导致重复索引键值的数组元素,只要该文档的索引键值不重复另一个文档的索引键值即可。

有关更多信息,请参见跨单独文档的唯一约束

 

四、局限性

1.复合多键索引

对于复合多键索引,每个索引文档最多可以有一个值是数组的索引字段,其。即:

 

  • 如果文档的一个以上的值是组数的字段要创建索引,则无法创建复合多键索引。例如,考虑一个包含以下文档的集合:
{ _id: 1, a: [ 1, 2 ], b: [ 1, 2 ], category: "AB - both arrays" }

       则不能在集合上创建复合多键索引{a:1,b:1},因为a和b字段都是数组。

 

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

       考虑一个包含以下文档的集合:       

{ _id: 1, a: [1, 2], b: 1, category: "A array" }

{ _id: 2, a: 1, b: [1, 2], category: "B array" }

      允许使用复合多键索引{a:1,b:1},因为对于每个文档,复合多键索引只有一个字段是一个数组。即没有文档的a和b字段值同时是数组。

      但是,在创建复合多键索引之后,如果您尝试插入a和b字段均为数组的文档,则MongoDB将使插入失败。

      如果字段是数组,并且数组的字段是嵌入式的,则嵌入式的字段也可以创建复合索引。例如,考虑一个包含以下文档的集合:

{ _id: 1, a: [ { x: 5, z: [ 1, 2 ] }, { z: [ 1, 2 ] } ] }

{ _id: 2, a: [ { x: 5 }, { z: 4 } ] }

您可以在{“ a.x”:1,“ a.z”:1}上创建复合索引。最多只能有一个索引字段可以是数组的限制也适用。

有关示例,请参见带有嵌入式文档的索引数组

也可以看看

 

2.排序

由于MongoDB 3.6中对数组字段的排序行为发生了变化,因此在对使用多键索引建立索引的数组上进行排序时,查询计划包括一个阻塞的SORT阶段。新的排序行为可能会对性能产生负面影响。

在阻塞式SORT中,必须在排序过程中使用所有输入参数,然后才能产生输出。在非阻塞或索引排序中,排序过程会扫描索引以按请求的顺序产生结果。

 

3.分片键

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

但是,如果分片键索引是复合索引的前缀,并且如果其他键(即不属于分片键的键)是对数组建立的索引,则允许该复合索引成为复合多键索引。复合多键索引可能会影响性能

 

4.哈希索引

哈希索引不能为多键。

5.覆盖查询

多键索引不能覆盖对数组字段的查询。

但是,从3.6开始,如果索引跟踪哪个字段或哪些字段导致索引成为多键,则多键索引可以覆盖非数组字段的查询。在MongoDB 3.4或更高版本中在MMAPv1 [#] _以外的存储引擎上创建的多键索引会跟踪此数据。

[2]从4.2版开始,MongoDB删除了不赞成使用的MMAPv1存储引擎。

6.整体查询数组字段

当查询过滤器指定整个数组的完全匹配项时,MongoDB可以使用多键索引查找查询数组的第一个元素,但不能使用多键索引扫描来查找整个数组。相反,在使用多键索引查找数组的第一个元素之后,MongoDB检索关联的文档并过滤其数组与查询中的数组匹配的文档。

例如,考虑包含以下文档的库存收集:

{ _id: 5, type: "food", item: "aaa", ratings: [ 5, 8, 9 ] }

{ _id: 6, type: "food", item: "bbb", ratings: [ 5, 9 ] }

{ _id: 7, type: "food", item: "ccc", ratings: [ 9, 5, 8 ] }

{ _id: 8, type: "food", item: "ddd", ratings: [ 9, 5 ] }

{ _id: 9, type: "food", item: "eee", ratings: [ 5, 9, 5 ] }

该集合在ratings 字段上具有多键索引:

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

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

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

MongoDB可以使用多键索引查找在ratings数组中具有5的文档。然后,MongoDB检索这些文档并过滤其ratings 数组等于查询数组[5、9]的文档。

 

7.$ expr

$ expr不支持多键索引。

 

五、例子

1.基本数组索引

考虑包含以下文档的survey集合

{ _id: 1, item: "ABC", ratings: [ 2, 5, 9 ] }

在字段ratings上创建索引:

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

由于ratings 字段包含一个数组,因此ratings 索引是多键的。该多键索引包含以下三个索引键,每个都指向同一文档:

  • 2,
  • 5,
  • 9。

2.带有嵌入式文档的索引数组

您可以在包含嵌套对象的数组字段上创建多键索引。

考虑具有以下格式文档的inventory集合

{

  _id: 1,

  item: "abc",

  stock: [

    { size: "S", color: "red", quantity: 25 },

    { size: "S", color: "blue", quantity: 10 },

    { size: "M", color: "blue", quantity: 50 }

  ]

}

{

  _id: 2,

  item: "def",

  stock: [

    { size: "S", color: "blue", quantity: 20 },

    { size: "M", color: "blue", quantity: 5 },

    { size: "M", color: "black", quantity: 10 },

    { size: "L", color: "red", quantity: 2 }

  ]

}

{

  _id: 3,

  item: "ijk",

  stock: [

    { size: "M", color: "blue", quantity: 15 },

    { size: "L", color: "blue", quantity: 100 },

    { size: "L", color: "red", quantity: 25 }

  ]

}

...

以下操作在stock.sizestock.quantity字段上创建多键索引:

db.inventory.createIndex( { "stock.size": 1, "stock.quantity": 1 } )

复合多键索引可以支持包含索引字段的查询,也支持仅包含索引前缀“ stock.size”的查询,如以下示例所示:

db.inventory.find( { "stock.size": "M" } )

db.inventory.find( { "stock.size": "S", "stock.quantity": { $gt: 20 } } )

有关MongoDB如何组合多键索引范围的详细信息,请参阅多键索引范围。有关复合索引和前缀的行为的更多信息,请参见复合索引和前缀

复合多键索引还可以支持排序操作,例如以下示例:

db.inventory.find( ).sort( { "stock.size": 1, "stock.quantity": 1 } )

db.inventory.find( { "stock.size": "M" } ).sort( { "stock.quantity": 1 } )

有关复合索引和排序操作的行为的更多信息,请参见使用索引对查询结果进行排序

 

上一篇:复合索引

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值