Sparse 索引

在本页面

Sparse索引只包含有索引字段的文档的条目,即使索引字段包含空值。索引会跳过任何缺少索引字段的文档。索引是**“稀疏的”**,因为它不包括一个集合的所有文档。相反,非稀疏索引包含集合中的所有文档,为那些不包含索引字段的文档存储空值。

重要的

从MongoDB 3.2开始,MongoDB提供了创建部分索引的选项。部分索引提供了sparse索引功能的超集。如果你正在使用MongoDB 3.2或更高版本,部分索引应该比稀疏索引更受欢迎。

创建sparse索引

要创建一个**“sparse”索引,使用db.collection.createIndex()方法,并将“sparse”选项设置为“true”。例如,下面的操作在mongo shell中创建了一个稀疏的索引在xmpp_id**字段的地址集合:

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

索引不会索引不包含**“xmpp_id”**字段的文档。

注意

不要将MongoDB中的sparse索引与其他数据库中的块级索引混淆。可以将它们看作具有特定过滤器的密集索引。

行为

“Sparse”索引和不完整结果

如果sparse索引会导致查询和排序操作的结果集不完整,MongoDB将不会使用该索引,除非hint()明确指定该索引。

例如,查询{x: {$exists: false}}不会在x字段上使用sparse索引,除非有明确提示。参见集合上的稀疏索引不能返回完整的结果了解详细的行为示例。

Changed in version 3.4.

如果在执行集合中所有文档的count()(i.e.带有空查询谓词)时包含 sparse索引count(),则即使sparse索引导致计数不正确,也会使用sparse索引。

db.collection.insert({ _id: 1, y: 1 } );
db.collection.createIndex( { x: 1 }, { sparse: true } );

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

要获得正确的计数,在对集合中的所有文档执行计数时,不要使用sparse索引的**“hint()**”。

db.collection.find().count();

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

默认情况下是“sparse”的索引

2dsphere(版本2) 2dgeoHaystack文本索引始终为sparse

Sparse复合索引

Sparse复合索引只包含升序/降序索引键将索引一个文档,只要该文档包含至少一个键。

包含一个地理空间的稀疏的复合索引键(即2 dsphere, 2d,或geoHaystack索引键)连同升序/降序索引键,只有地理空间的存在领域(s)文档中确定索引文档的引用。

对于包含text索引键和升序/降序索引键的sparse复合索引,只有**“text”**索引字段的存在决定该索引是否引用一个文档。

“Sparse”和“unique”属性

一个**“sparse”**和unique索引可以防止集合的文档具有一个字段的重复值,但允许多个文档忽略该键。

例子

在集合上创建sparse索引

考虑一个包含以下文档的集合**“scores”**:

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

集合在**“score”字段上有一个sparse**索引:

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

然后,下面对scores集合的查询使用sparse索引返回score字段小于(' $lt ')的文档90:

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

由于userid的文档"newbie"不包含该 score字段,因此不满足查询条件,因此查询可以使用sparse索引返回结果:

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

集合上的sparse索引不能返回完整的结果

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

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

集合在**“score”**字段上有一个sparse索引:

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

因为userid的文档 "newbie"不包含score字段,所以sparse索引不包含该文档的条目。

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

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

即使是按索引字段排序,MongoDB也不会选择sparse索引来完成查询,以返回完整的结果:

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

要使用sparse索引,显式地用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 }

也可以看看:

explain()Analyze Query Performance

具有唯一约束的sparse索引

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

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

您可以使用以下操作在score字段上创建一个unique constraint和sparse过滤器:

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

该索引将允许插入具有该score字段唯一值或不包含该score字段的文档。这样,鉴于scores集合中现有的文档,索引允许进行以下插入操作

db.scores.insert( { "userid": "AAAAAAA", "score": 43 } )
db.scores.insert( { "userid": "BBBBBBB", "score": 34 } )
db.scores.insert( { "userid": "CCCCCCC" } )
db.scores.insert( { "userid": "DDDDDDD" } )

但是,索引不允许添加以下文件,因为文件已经存在,其score值为8290:

db.scores.insert( { "userid": "AAAAAAA", "score": 82 } )
db.scores.insert( { "userid": "BBBBBBB", "score": 90 } )

最后更新于