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

稀疏索引

本页内容

  • 创建稀疏索引
  • 行为
  • 示例

稀疏索引仅包含具有索引字段的文档条目,即使索引字段包含空值。索引会跳过任何缺少索引字段的文档。由于它不包括集合中的所有文档,因此索引是“稀疏”的。相比之下,非稀疏索引包含集合中的所有文档,对于不包含索引字段的文档存储空值。

重要

MongoDB 提供了创建部分索引的选项。部分索引提供了稀疏索引功能的一个超集。应优先选择部分索引而非稀疏索引。

要创建稀疏索引,请使用 db.collection.createIndex() 方法并将 sparse 选项设置为 true

例如,以下操作在mongosh 中创建了一个 addresses 集合中 xmpp_id 字段的稀疏索引

db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )

该索引不索引不包含 xmpp_id 字段的文档。

注意

不要将MongoDB中的稀疏索引与其他数据库中的块级索引混淆。把它们想象成具有特定过滤器的密集索引。

如果稀疏索引会导致查询和排序操作的结果集不完整,除非显式地指定了索引,否则MongoDB不会使用该索引。

例如,查询{ x: { $exists: false } }在未显式提示的情况下,不会使用字段x上的稀疏索引。请参阅集合上的稀疏索引无法返回完整结果以了解行为示例。

如果您在执行集合中所有文档的计数(即空查询谓词)时指定了hint()来指定稀疏索引,即使稀疏索引导致计数不正确,也会使用稀疏索引。

db.collection.insertOne( { _id: 1, y: 1 } );
db.collection.createIndex( { x: 1 }, { sparse: true } );
db.collection.find().hint( { x: 1 } ).count();

为了获取正确的计数,在执行集合中所有文档的计数时,不要使用稀疏索引进行hint()

db.collection.find().count();
db.collection.createIndex( { y: 1 } );
db.collection.find().hint( { y: 1 } ).count();

以下索引类型始终是稀疏的

组合索引可以包含不同类型的稀疏索引。索引类型的组合决定了组合索引如何匹配文档。

下表总结了包含不同类型稀疏索引的组合索引的行为

组合索引组件
组合索引行为
升序索引
降序索引
仅索引包含至少一个键值的文档。
升序索引
降序索引
仅当文档包含一个地理空间字段值时才索引文档。不索引升序或降序索引中的文档。
升序索引
降序索引
仅当文档匹配一个文本字段时才索引文档。不索引升序或降序索引中的文档。

同时具有稀疏性和唯一性的索引可以防止集合中出现具有重复字段值的文档,但允许存在多个省略键的文档。

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

{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }

该集合在字段 score 上有一个稀疏索引

db.scores.createIndex( { score: 1 } , { sparse: true } )

然后,对 scores 集合的以下查询使用稀疏索引来返回具有 score 字段小于 ($lt) 90

db.scores.find( { score: { $lt: 90 } } )

由于用户id为 "newbie" 的文档不包含 score 字段,因此不符合查询条件,查询可以使用稀疏索引来返回结果

{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }

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

{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }

该集合在字段 score 上有一个稀疏索引

db.scores.createIndex( { score: 1 } , { sparse: true } )

因为用户ID为“newbie”的文档不包含score字段,所以稀疏索引不包含该文档的条目。

考虑以下查询以返回scores集合中的所有文档,并按score字段排序

db.scores.find().sort( { score: -1 } )

尽管排序是根据索引字段进行的,但MongoDB不会选择稀疏索引来满足查询以返回完整结果

{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }

要使用稀疏索引,请显式指定索引,使用hint():

db.scores.find().sort( { score: -1 } ).hint( { score: 1 } )

使用索引只返回包含score字段的文档

{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }

提示

另请参阅

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

{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }

你可以使用以下操作创建一个具有唯一约束和稀疏筛选器的索引,用于对score字段进行操作

db.scores.createIndex( { score: 1 } , { sparse: true, unique: true } )

此索引将允许插入具有唯一score字段值或没有score字段的文档。因此,考虑到scores集合中的现有文档,索引允许以下插入操作

db.scores.insertMany( [
{ "userid": "newbie", "score": 43 },
{ "userid": "abby", "score": 34 },
{ "userid": "nina" }
] )

但是,由于已存在具有score值为8290的文档,因此索引不允许添加以下文档。

db.scores.insertMany( [
{ "userid": "newbie", "score": 82 },
{ "userid": "abby", "score": 90 }
] )

从MongoDB 5.0开始,可以在单个集合上存在具有相同唯一稀疏唯一非稀疏索引,它们的键模式相同。

此示例创建了多个具有相同键模式和不同稀疏选项的索引。

db.scoreHistory.createIndex( { score : 1 }, { name: "unique_index", unique: true } )
db.scoreHistory.createIndex( { score : 1 }, { name: "unique_sparse_index", unique: true, sparse: true } )

您还可以创建具有相同键模式的带和不带稀疏选项的基本索引。

db.scoreHistory.createIndex( { score : 1 }, { name: "sparse_index", sparse: true } )
db.scoreHistory.createIndex( { score : 1 }, { name: "basic_index" } )

返回

部分