稀疏索引仅包含具有索引字段的文档的条目,即使索引字段包含 null 值也是如此。该索引将跳过缺少索引字段的所有文档。索引是“稀疏”的,因为它不包括集合的所有文档。相比之下,非稀疏索引包含集合中的所有文档,为那些不包含索引字段的文档存储 null 值。
重要
部分索引可以用作稀疏索引,但也支持字段是否存在以外的条件的过滤表达式。如果需要精确筛选,请使用部分索引进行更好的控制。
创建稀疏索引
要创建稀疏索引,请使用 db.collection.createIndex() 方法,并将 sparse 选项设置为 true。
例如,mongosh 中的以下操作在 movies 集合的 plot 字段上创建稀疏索引:
db.movies.createIndex( { "plot": 1 }, { sparse: true } )
该索引不会索引不包含 plot 字段的文档。
注意
请勿将MongoDB中的稀疏索引与其他数据库中的区块级索引混淆。将它们视为具有特定过滤的密集索引。
行为
索引稀疏,结果不完整
如果稀疏索引会导致查询和排序操作的结果集不完整,则除非 hint() 显式指定该索引,否则 MongoDB 不会使用该索引。
例如,除非显式提示,否则查询 { plot: { $exists: false } } 不会在 plot 字段上使用稀疏索引。有关详细行为的示例,请参阅集合上的稀疏索引无法返回完整结果。
当您对集合中所有文档执行 count() 时(即,采用空查询谓词),您要纳入指定稀疏索引的 hint(),即便该稀疏索引产生错误计数也要使用。
示例,在 movies集合的 rated字段上创建稀疏索引。
db.movies.createIndex( { rated: 1 }, { sparse: true } )
如果计算 movies集合中的文档数并包含指定该稀疏索引的提示,则该操作仅返回包含 rated字段的文档。
db.movies.countDocuments( {}, { hint: { rated: 1 } } )
要获得movies 集合中文档数量的正确计数,在对集合中的所有文档进行计数时,请勿使用稀疏索引hint() 。
db.movies.countDocuments()
默认情况下稀疏的索引
以下索引类型始终是稀疏的:
稀疏复合索引
复合索引可以包含不同类型的稀疏索引。索引类型的组合决定了复合索引与文档的匹配方式。
本表汇总了包含不同类型稀疏索引的复合索引的行为:
复合索引组件 | 复合索引行为 |
|---|---|
Ascending indexes Descending indexes | 仅对至少包含一个键值的文档进行索引。 |
仅当文档包含一个 | |
仅当文档与一个 |
稀疏和唯一属性
既稀疏又唯一的索引可防止集合的文档具有重复的字段值,但允许多个省略该键的文档。
示例
在集合上创建稀疏索引
以下示例在字段password 上创建稀疏索引:
db.users.createIndex( { password: 1 } , { sparse: true } )
然后,对 users集合的以下查询使用稀疏索引返回具有 password字段的文档:
db.users.find( { password: { $exists: true } } ).sort({ password: 1 }).limit(5)
如果用户不包含 password字段,则查询不会返回该用户。
集合上的稀疏索引无法返回完整结果
考虑 movies集合,其中某些文档没有 plot字段。
以下示例在字段plot 上创建稀疏索引:
db.movies.createIndex( { "plot": 1 }, { sparse: true } )
以下查询返回 movies 集合中的所有文档(按 plot 字段排序):
db.movies.find().sort( { plot: -1 } )
即使按索引字段排序,如果movies 集合中的某些文档没有plot 字段, MongoDB也不会选择稀疏索引来完成查询以返回完整结果。
要使用稀疏索引,请用 hint() 显式指定该索引:
db.movies.find().sort( { plot: -1 } ).hint( { plot: 1 } ).limit(5)
此查询仅返回 movies集合中包含 plot字段的文档。
具有唯一性约束的稀疏索引
以下操作在 中的 字段上创建具有唯一约束和稀疏过滤索引:passwordusers
db.users.createIndex( { password: 1 } , { sparse: true, unique: true } )
该索引允许插入具有唯一 password 字段值或不包含 password 字段的文档。因此,鉴于 users 集合中的现有文档,该索引允许以下插入操作:
db.users.insertMany( [ { "name": "Jon Snow", "email": "jon@gameofthron.es", "password": "$2b$12$newHashedPassword1234567890ABC" }, { "name": "Sansa Stark", "email": "sansa@gameofthron.es", "password": "$2b$12$anotherNewPassword1234567890DEF" }, { "name": "Bran Stark", "email": "bran@gameofthron.es" } ] )
但是,该索引不允许添加包含集合中已存在的电子邮件地址的文档。
稀疏和非稀疏唯一索引
从 MongoDB 5.0 开始,具有相同键模式的唯一稀疏和唯一非稀疏索引可以存在于同一个集合中。
唯一和稀疏索引创建
此示例将使用相同的键模式和不同的 sparse 选项来创建多个索引:
db.users.createIndex( { password : 1 }, { name: "unique_index", unique: true } )
db.users.createIndex( { password : 1 }, { name: "unique_sparse_index", unique: true, sparse: true } )
基本索引和稀疏索引创建
还可以使用和不使用稀疏选项创建具有相同键模式的基本索引:
db.users.createIndex( { password : 1 }, { name: "sparse_index", sparse: true } )
db.users.createIndex( { password : 1 }, { name: "basic_index" } )