复合索引
MongoDB 支持复合索引,其中单个索引结构保存对集合文档中多个字段[1]的引用。 下图说明了两个字段上的复合索引的示例:
[1] | MongoDB对任何复合索引施加 32 字段的复合索引 |
复合索引可以支持匹配多个字段的查询。
兼容性
您可以对 MongoDB Atlas中托管的部署使用复合索引。
要了解有关为 MongoDB Atlas 中托管的部署管理索引的更多信息,请参阅创建、查看、删除和隐藏索引。
创建复合索引
要创建复合索引,请使用类似于以下原型的操作:
db.collection.createIndex( { <field1>: <type>, <field2>: <type2>, ... } )
索引字段的顺序对给定查询的特定索引的有效性有很大影响。For most compound indexes, following the ESR (Equality, Sort, Range) rule helps to create efficient indexes.
重要
从 MongoDB 4.4 开始:
复合索引可以包含单个哈希索引字段。
如果尝试创建包含多个哈希索引字段的复合索引,则会收到错误消息。
在 MongoDB 4.2 或更早版本中:
复合索引不得包含哈希索引字段。
如果尝试创建包含哈希索引字段的复合索引,则会收到错误消息。
考虑一个名为 products
的集合,其中包含类似于以下文档的文档:
{ "_id": ObjectId(...), "item": "Banana", "category": ["food", "produce", "grocery"], "location": "4th Street Store", "stock": 4, "type": "cases" }
以下操作在item
和stock
字段上创建升序索引:
db.products.createIndex( { "item": 1, "stock": 1 } )
复合索引中列出的字段顺序很重要。 该索引将包含对文档的引用,这些文档首先按item
字段的值排序,然后在item
字段的每个值中按 stock 字段的值排序。 有关详细信息,请参阅排序顺序。
复合索引除了支持匹配所有索引字段的查询外,还支持匹配索引字段前缀的查询。 也就是说,索引支持对item
字段以及item
和stock
字段的查询:
db.products.find( { item: "Banana" } ) db.products.find( { item: "Banana", stock: { $gt: 5 } } )
有关详细信息,请参阅前缀。
排序顺序
索引按升序 ( 1
) 或降序 ( -1
)存储对字段的引用。 对于单字段索引,键的排序顺序并不重要,因为MongoDB可以沿任一方向遍历索引。 但是,对于复合索引,排序顺序对于确定索引是否可以支持排序操作很重要。
考虑一个collectionevents
,其中包含具有字段username
和date
的文档。应用程序可以发出查询,返回的结果首先按升序username
值排序,然后按降序(即从最近到最后) date
值排序,例如:
db.events.find().sort( { username: 1, date: -1 } )
或查询返回的结果首先按降序username
值排序,然后按升序date
值排序,例如:
db.events.find().sort( { username: -1, date: 1 } )
以下索引可以支持这两种排序操作:
db.events.createIndex( { "username" : 1, "date" : -1 } )
但是,上述索引不支持先按username
值升序排序,然后再按date
值升序排序,如下所示:
db.events.find().sort( { username: 1, date: 1 } )
有关排序顺序和复合索引的更多信息,请参阅使用索引对查询结果进行排序。
前缀
索引前缀是索引字段的起始子集。例如,考虑以下复合索引:
{ "item": 1, "location": 1, "stock": 1 }
该索引具有以下索引前缀:
{ item: 1 }
{ item: 1, location: 1 }
对于复合索引,MongoDB 可以使用索引来支持对索引前缀的查询。 因此,MongoDB 可以使用该索引对以下字段进行查询:
item
字段。item
字段和location
字段,item
字段、location
字段和stock
字段。
MongoDB 还可以使用索引支持对item
和stock
字段的查询,因为item
字段对应于前缀。 但是,在这种情况下,索引在支持查询方面的效率不如索引仅位于item
和stock
上。
item
由于对stock
和 的查询省略了location
索引前缀,因此无法使用stock
之后的location
索引字段。只有索引中的item
字段可以支持此查询。 有关更多信息,请参阅创建索引以支持查询。 索引:
匹配
item
的键。在
IXSCAN
阶段对stock
字段执行筛选。返回筛选后的结果。
例如,考虑对"item":
"saccharomyces cerevisiae"
和"stock": 60
的查询。 如果collection包含 10000 个与"item":
"saccharomyces cerevisiae"
匹配的文档,而其中只有 100 个与"stock": 60
匹配的文档,则该查询将检查 10000 个键。在IXSCAN
阶段,查询按stock
字段筛选这些键,并且仅向下一阶段返回 100 个结果。
MongoDB 无法使用该索引来支持包含以下字段的查询,因为如果没有item
字段,所列字段均不对应于前缀索引:
location
字段。stock
字段,或location
和stock
字段。
如果您的集合同时具有复合索引和前缀索引(例如 { a: 1, b: 1 }
和{ a: 1 }
),如果两个索引都没有稀疏或唯一约束,那么您可以删除前缀上的索引(例如 { a: 1 }
)。 MongoDB 将在所有需要使用前缀索引的情况下使用复合索引。
索引并集
从 2.6 版本开始,MongoDB 可以使用索引交集来完成查询。 选择创建支持查询的复合索引还是依赖索引交集取决于系统的具体情况。 有关更多详细信息,请参阅索引交集和复合索引。
稀疏复合索引
复合索引可以包含不同类型的稀疏索引。索引类型的组合决定了复合索引与文档的匹配方式。
本表汇总了包含不同类型稀疏索引的复合索引的行为:
复合索引组件 | 复合索引行为 |
---|---|
Ascending indexes Descending indexes | 仅对至少包含一个键值的文档进行索引。 |
仅当文档包含一个 geospatial 字段的值时,才为文档编制索引。不在升序或降序索引中索引文档。 | |
仅当文档与一个 text 字段匹配时,才为文档编制索引。不在升序或降序索引中索引文档。 |
其他注意事项
在索引构建期间,应用程序可能会遇到性能下降或要索引集合的读/写权限受限的问题。
有关索引构建过程的更多信息,请参阅填充collection上的索引构建,特别是复制环境中的索引构建部分。
某些驱动程序使用NumberLong(1)
而不是1
来指定索引顺序。 生成的索引是相同的。