Sparse Indexes
在本页面
稀疏索引仅包含具有索引字段的文档条目,即使索引字段包含空值也是如此。索引会跳过缺少索引字段的所有文档。索引是“稀疏的”,因为它不包括集合的所有文档。相比之下,非稀疏索引包含集合中的所有文档,为那些不包含索引字段的文档存储空值。
Important
在版本 3.2 中进行了更改:从 MongoDB 3.2 开始,MongoDB 提供了创建partial indexes的选项。部分索引提供了稀疏索引功能的超集。如果您使用的是 MongoDB 3.2 或更高版本,则partial indexes应该比稀疏索引更可取。
创建稀疏索引
要创建sparse
索引,请使用db.collection.createIndex()方法并将sparse
选项设置为true
。例如,在mongo shell 中的以下操作在addresses
集合的xmpp_id
字段上创建稀疏索引:
db.addresses.createIndex( { "xmpp_id": 1 }, { sparse: true } )
索引不索引不包含xmpp_id
字段的文档。
Note
不要将 MongoDB 中的稀疏索引与其他数据库中的block-level索引混淆。可以将它们视为具有特定过滤器的密集索引。
Behavior
稀疏索引和不完整结果
如果稀疏索引会导致查询和排序操作的结果集不完整,除非hint()明确指定索引,否则 MongoDB 将不会使用该索引。
例如,除非明确提示,否则查询{ x: { $exists: false } }
不会在x
字段上使用稀疏索引。有关详细行为的示例,请参见集合上的稀疏索引无法返回完整结果。
在版本 3.4 中更改。
如果对集合中的所有文档执行count()时(即查询谓词为空),当您包含hint()
时指定sparse index时,即使稀疏索引导致计数错误,也会使用稀疏索引。
db.collection.insert({ _id: 1, y: 1 } );
db.collection.createIndex( { x: 1 }, { sparse: true } );
db.collection.find().hint( { x: 1 } ).count();
为了获得正确的计数,在对集合中的所有文档进行计数时,请勿使用sparse index hint()
。
db.collection.find().count();
db.collection.createIndex({ y: 1 });
db.collection.find().hint({ y: 1 }).count();
默认情况下稀疏的索引
2 dsphere(第 2 版),2d,geoHaystack和text索引始终为sparse
。
稀疏复合索引
仅包含升序/降序索引键的稀疏compound indexes将对文档构建索引,只要该文档包含至少一个键即可。
对于包含地理空间键(即2dsphere,2d或geoHaystack索引键)以及升/降索引键的稀疏复合索引,只有文档中地理空间字段的存在才能确定索引是否引用了文件。
对于包含text索引键以及升/降索引键的稀疏复合索引,只有text
索引字段的存在才能确定索引是否引用文档。
稀疏且独特的属性
同时为sparse
和unique的索引可防止集合使文档的字段具有重复的值,但允许多个文档省略该键。
Examples
在集合上创建稀疏索引
考虑一个包含以下文档的集合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
字段上使用unique constraint和稀疏过滤器创建索引:
db.scores.createIndex( { score: 1 } , { sparse: true, unique: true } )
该索引将允许插入具有score
字段或的唯一值的文档,但不包括score
字段。因此,鉴于scores
集合中的现有文档,索引允许以下insert operations:
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
值为82
和90
的文档已经存在:
db.scores.insert( { "userid": "AAAAAAA", "score": 82 } )
db.scores.insert( { "userid": "BBBBBBB", "score": 90 } )