稀疏索引¶
稀疏索引中值存储那些有被索引键的文档的索引项,即使被索引键的值是null也会被索引(译者注:请注意,这里对null的处理和那些特殊索引的默认稀疏特性有细微差别,比如文本索引,2d索引等)。索引会跳过所有不包含被索引键的文档。这个索引之所以称为 “稀疏” 是因为它并不包括集合中的所有文档。与之相反,非稀疏的索引会索引每一篇文档,如果一篇文档不含被索引键则为它存储一个null值。
如果希望创建一个 稀疏 索引, 请在 db.collection.ensureIndex() 方法中将 sparse 选项设为 true 。例如,在 mongo shell中执行如下操作可以在 addresses 集合的 xmpp_id 键上建立一个稀疏索引:
db.addresses.ensureIndex( { "xmpp_id": 1 }, { sparse: true } )
注解
不要把MongoDB中的稀疏索引和其他数据库中的 block-level 索引相混淆了。把它们看作带有特殊过滤器的密集索引。
特性¶
关于 稀疏 索引和不完整结果¶
在 2.6 版更改.
如果一个索引会导致查询或者排序的结果集是不完整的,那么MongoDB将不会使用这个索引,除非用户使用 hint() 方法来显示指定索引。
例如,查询 { x: { $exists: false } } 将不会使用 x 键上的稀疏索引,除非显示的hint。参见 在A集合上的稀疏索引不会返回完整结果 来了解有关这个特性的具体例子。
默认是 稀疏 的索引¶
2dsphere (version 2), 2d, geoHaystack, 和 text 这些索引总是 稀疏 的(译者注:请注意,这些索引对null的处理和这里的稀疏索引的处理有细微差别,不要混淆了!)。
例子¶
在A集合上创建稀疏索引¶
假设集合 scores 有如下文档:
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
集合在 score 键上有一个稀疏索引:
db.scores.ensureIndex( { score: 1 } , { sparse: true } )
那么,在 scores 集合上执行如下查询,将会利用稀疏索引来返回包含了 score 键且值小于 ($lt) 90 的文档:
db.scores.find( { score: { $lt: 90 } } )
由于userid为 "newbie" 的文档不包含 score 键,因此无法满足查询条件,那么查询可以利用稀疏索引来返回如下结果:
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
在A集合上的稀疏索引不会返回完整结果¶
假设集合 scores 有如下文档:
{ "_id" : ObjectId("523b6e32fb408eea0eec2647"), "userid" : "newbie" }
{ "_id" : ObjectId("523b6e61fb408eea0eec2648"), "userid" : "abby", "score" : 82 }
{ "_id" : ObjectId("523b6e6ffb408eea0eec2649"), "userid" : "nina", "score" : 90 }
集合在 score 键上有一个稀疏索引:
db.scores.ensureIndex( { score: 1 } , { sparse: true } )
由于userid为 "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.ensureIndex( { score: 1 } , { sparse: true, unique: true } )
这个索引 允许 插入 score 键上的值是唯一或者不包含 score 键的文档。有如下 插入 :
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 } )