MongoDB部分索引只为那些在一个集合中,满足指定的筛选条件的文档创建索引。由于部分索引是一个集合文档的一个子集,因此部分索引具有较低的存储需求,并降低了索引创建和维护的性能成本。部分索引通过指定过滤条件来创建,可以为MongoDB支持的所有索引类型使用部分索引。
一、语法描述
创建部分索引语法db.collection.createIndex(keys, options)options可以使用partialFilterExpression,即部分过滤表达式,其类型为文档类型过滤表达式通常包括以下equality expressions (i.e. field: value or using the $eq operator),$exists: true expression,$gt, $gte, $lt, $lte expressions,$type expressions,$and operator at the top-level only过滤表达式使用示例:db.persons.createIndex({name:1},{partialFilterExpression:{age: {$gt:25}}})
二、演示部分索引
1、演示环境
> db.version()3.2.10//演示中用到的文档,可参考:http://blog.csdn.net/leshami/article/details/52672310> db.persons.find().pretty().limit(1){"_id" : ObjectId("5812cbaaa129eed14b46458d"),"name" : "robinson.cheng","age" : 25,"email" : "robinson.cheng@qq.com","score" : {"c" : 89, //Author : Leshami"m" : 96, //Blog : http://blog.csdn.net/leshami"e" : 87},"country" : "USA","books" : ["JS","C++","EXTJS","MONGODB"]}> db.persons.find().count()11
2、创建部分索引
//基于age列创建大于25岁的部分索引> db.persons.createIndex({country:1},{partialFilterExpression: {age: {$gt:25}}}){"createdCollectionAutomatically" : false,"numIndexesBefore" : 1,"numIndexesAfter" : 2,"ok" : 1}//查询谓词条件为{country:"China",age:{$gt:25},年龄大于25> db.persons.find({country:"China",age:{$gt:25}}).explain(){"queryPlanner" : {......"winningPlan" : {"stage" : "FETCH","filter" : {"age" : {"$gt" : 25}},"inputStage" : {"stage" : "IXSCAN","keyPattern" : {"country" : 1},"indexName" : "country_1",......."isPartial" : true, //这里描述为部分索引"indexVersion" : 1,"direction" : "forward","indexBounds" : {"country" : ["[\"China\", \"China\"]"......"ok" : 1}//查询谓词条件为{country:"China",age:{$gte:25}},年龄大于等于25> db.persons.find({country:"China",age:{$gte:25}}).explain(){"queryPlanner" : {........"winningPlan" : {"stage" : "COLLSCAN", //此时为集合扫描方式"filter" : {"$and" : [{"country" : {"$eq" : "China"}},{"age" : {"$gte" : 25......"ok" : 1}//查询谓词为{country:"China",age:{$gte:26}},年龄大于等于26> db.persons.find({country:"China",age:{$gte:26}}).explain(){"queryPlanner" : {......"winningPlan" : {"stage" : "FETCH","filter" : {"age" : {"$gte" : 26}},"inputStage" : {"stage" : "IXSCAN",//此时为索引扫描,因为26大于索引值25"keyPattern" : {"country" : 1},"indexName" : "country_1",......"isPartial" : true,"indexVersion" : 1,"direction" : "forward","indexBounds" : {"country" : ["[\"China\", \"China\"]"......"ok" : 1}//谓词{country:"China",age:{$lt:25},年龄小于25> db.persons.find({country:"China",age:{$lt:25}}).explain(){"queryPlanner" : {......."winningPlan" : {"stage" : "COLLSCAN", //小于25为集合扫描方式"filter" : {"$and" : [{"country" : {"$eq" : "China"}},{"age" : {"$lt" : 25......"ok" : 1}
三、创建部分唯一索引的一些限制
部分索引只为集合中那些满足指定的筛选条件的文档创建索引。如果你指定的partialfilterexpression和唯一约束、那么唯一性约束只适用于满足筛选条件的文档。具有唯一约束的部分索引不会阻止不符合唯一约束且不符合过滤条件的文档的插入。示例文档> db.users.insertMany([{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 },{ "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 },{ "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }])//为集合添加索引> db.users.createIndex({ username: 1 },{ unique: true, partialFilterExpression: { age: { $gte: 21 } } })//在集合users上插入用户名相同的文档,收到了重复键的错误提示> db.users.insert( { username: "david", age: 27 } )WriteResult({"nInserted" : 0,"writeError" : {"code" : 11000,"errmsg" : "E11000 duplicate key error collection: test.users index: username_1 dup key: { : \"david\" }"}})//下面插入年龄小于部分索引值或者age键为空的同用户名文档,可以成功插入。//也就是说对于不在部分索引限制之类的其他键值重复是允许的> db.users.insert( { username: "david", age: 20 } )WriteResult({ "nInserted" : 1 })> db.users.insert( { username: "amanda" } )WriteResult({ "nInserted" : 1 })> db.users.insert( { username: "rajiv", age: null } )WriteResult({ "nInserted" : 1 })
四、部分索引与稀疏索引的比对
稀疏索引指的是在一个集合中文档A,C中包含某些列,如Key_A,而其他文档不包含Key_A,Key_A上的索引为稀疏索引部分索引代表的稀疏索引提供的功能的一个超集,应该优先于稀疏索引部分索引主要是针对那些满足条件的文档(非字段缺失)创建索引,比稀疏索引提供了更具有表现力稀疏索引是文档上某些字段的存在与否,存在则为其创建索引,否则该文档没有索引键如下示例,可以使用部分索引达到实现稀疏索引相同的效果(在名字列上过滤表达式为判断列是否存在)db.contacts.createIndex({ name: 1 },{ partialFilterExpression: { name: { $exists: true } } })基于非索引列过滤的部分索引如下示例,过滤表达式为非索引列,及email列db.contacts.createIndex({ name: 1 },{ partialFilterExpression: { email: { $exists: true } } }) 在这种情况下,索引要如何才能被使用到呢?查询谓词在email字段上应该包含一个非空的匹配,同时也要使用name作为过滤条件,如下://下面的查询将使用索引db.contacts.find( { name: "xyz", email: { $regex: /\.org$/ } } )//下面的查询将不会使用到索引db.contacts.find( { name: "xyz", email: { $exists: false } } )
五、小结
a、部分索引就是带有过滤条件的索引,即索引只存在与某些文档之上
b、满足过滤条件的文档在查询时,其执行计划将使用该列上的索引,否则不会被使用
c、稀疏索引与部分索引的差异是一个是基于某些文档存在的列,一个是列上的某些匹配条件的值
d、可以基于某个列上创建索引,而在另外的列来使用过滤条件
六、更多参考
MongoDB 单键(列)索引
MongoDB 复合索引
MongoDB 多键索引
MongoDB执行计划获取(db.collection.explain())
MongoDB 唯一索引