本章内容:
- 创建局部索引
- 行为
- 限制条件
- 例子
3.2版中的新功能。
局部索引仅对集合中符合指定过滤器表达式的文档建立索引。通过对集合中文档的子集进行索引,局部索引具有较低的存储需求,并降低了索引创建和维护的性能成本。
一、创建局部索引
要创建局部索引,需要在使用db.collection.createIndex()方法创建索引时候, 指定partialFilterExpression选项。 partialFilterExpression选项可以使用以下命令指定过滤条件的文档:
例如,以下操作将创建一个复合索引,该索引仅对rating字段大于5的文档建立索引。
db.restaurants.createIndex(
{ cuisine: 1, name: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
可以为所有MongoDB索引类型指定partialFilterExpression选项。
二、行为
1.范围查询
如果使用索引导致结果集不完整,则MongoDB不会将局部索引用于查询或排序操作。
若要使用局部索引,查询必须包含过滤器表达式(或指定过滤器表达式的子集的修改后的过滤器表达式)作为其查询条件的一部分。
例如,给定以下索引:
db.restaurants.createIndex(
{ cuisine: 1 },
{ partialFilterExpression: { rating: { $gt: 5 } } }
)
以下查询可以使用索引,因为查询谓词包括条件rating: { $gte: 8 },它与由索引过滤器表达式rating: { $gte: 5 }匹配的文档子集匹配:
db.restaurants.find( { cuisine: "Italian", rating: { $gte: 8 } } )
但是,以下查询不能使用Cuisine字段上的局部索引,因为使用索引会导致结果集不完整。具体来说,查询谓词包括条件等级:{$ lt:8},而索引具有过滤器等级:{$ gt:5}。也就是说,查询{Cuisine:“ Italian”,rating:{$ lt:8}}与索引相比,匹配的文档(例如,评级为1的意大利餐馆)更多。
db.restaurants.find( { cuisine: "Italian", rating: { $lt: 8 } } )
同样,以下查询不能使用局部索引,因为查询谓词不包含过滤器表达式,并且使用索引将返回不完整的结果集。
db.restaurants.find( { cuisine: "Italian" } )
2.与稀疏指数的比较
提示
局部索引代表稀疏索引提供的功能的超集,应优先于稀疏索引。
局部索引比稀疏索引索引提供了一种更具表达力的机制,可用于指定要对哪些文档建立索引。
稀疏索引仅根据索引字段的存在来选择要索引的文档,对于复合索引,则仅根据索引字段的存在来进行索引。
局部索引根据指定的过滤器确定索引条目。筛选器可以包含除索引键以外的其他字段,并且可以指定除存在检查以外的条件。例如,局部索引可以实现与稀疏索引相同的行为:
db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { name: { $exists: true } } }
)
此局部索引支持与名称字段上的稀疏索引相同的查询。
但是,局部索引还可以在索引键以外的其他字段上指定过滤器表达式。例如,以下操作将创建局部索引,其中该索引位于名称字段上,而过滤表达式位于电子邮件字段上:
db.contacts.createIndex(
{ name: 1 },
{ partialFilterExpression: { email: { $exists: true } } }
)
为了使查询优化器选择此局部索引,查询谓词必须在名称字段上包含条件,并在电子邮件字段上包含非空匹配。
例如,以下查询可以使用索引,因为它既包含名称字段上的条件,又包含电子邮件字段上的非空匹配项:
db.contacts.find( { name: "xyz", email: { $regex: /\.org$/ } } )
但是,以下查询无法使用索引,因为它在email字段上包含空匹配,这是过滤器表达式{email:{$ exists:true}}不允许的:
db.contacts.find( { name: "xyz", email: { $exists: false } } )
三、限制条件
在MongoDB中,您不能创建仅在选项上有所不同的多个索引版本。因此,您不能创建仅因过滤器表达式而不同的多个局部索引。
您不能同时指定partialFilterExpression选项和sparse(稀疏)选项。
MongoDB 3.0或更早版本不支持局部索引。要使用局部索引,必须使用MongoDB 3.2或更高版本。对于分片群集或副本集,所有节点必须为3.2或更高版本。
_id索引不能是局部索引。
分片键索引不能是局部索引。
四、例子
1.在集合上创建局部索引
考虑一个集合restaurants,其中包含类似于以下内容的文档
{
"_id" : ObjectId("5641f6a7522545bc535b5dc9"),
"address" : {
"building" : "1007",
"coord" : [
-73.856077,
40.848447
],
"street" : "Morris Park Ave",
"zipcode" : "10462"
},
"borough" : "Bronx",
"cuisine" : "Bakery",
"rating" : { "date" : ISODate("2014-03-03T00:00:00Z"),
"grade" : "A",
"score" : 2
},
"name" : "Morris Park Bake Shop",
"restaurant_id" : "30075445"
}
您可以在borough 和 cuisine字段添加局部索引,仅对rating.grade是A的文档编制索引:
db.restaurants.createIndex(
{ borough: 1, cuisine: 1 },
{ partialFilterExpression: { 'rating.grade': { $eq: "A" } } }
)
然后,对restaurants集合的以下查询使用局部索引来返回borough 是Bronx并且rating.grade等于A的restaurants结果集:
db.restaurants.find( { borough: "Bronx", 'rating.grade': "A" } )
但是,以下查询不能使用局部索引,因为查询表达式不包括rating.grade字段:
db.restaurants.find( { borough: "Bronx", cuisine: "Bakery" } )
2.具有唯一约束的局部索引
局部索引仅索引集合中符合指定过滤器表达式的文档。如果同时指定了partialFilterExpression和唯一性约束,则唯一性约束仅适用于满足过滤器表达式的文档。如果文档不符合过滤条件,则具有唯一约束的局部索引不会阻止插入违反唯一约束的文档。
例如,集合users包含以下文档:
{ "_id" : ObjectId("56424f1efa0358a27fa1f99a"), "username" : "david", "age" : 29 }
{ "_id" : ObjectId("56424f37fa0358a27fa1f99b"), "username" : "amanda", "age" : 35 }
{ "_id" : ObjectId("56424fe2fa0358a27fa1f99c"), "username" : "rajiv", "age" : 57 }
以下操作将创建一个索引,该索引指定了对username 字段的唯一约束和局部过滤表达式age:{$ gte:21}。
db.users.createIndex(
{ username: 1 },
{ unique: true, partialFilterExpression: { age: { $gte: 21 } } }
)
该索引防止插入以下文档,因为已经存在具有指定username的文档,并且age字段大于21:
db.users.insert( { username: "david", age: 27 } )
db.users.insert( { username: "amanda", age: 25 } )
db.users.insert( { username: "rajiv", age: 32 } )
但是,由于唯一约束仅适用于age大于或等于21岁的文档,因此允许插入以下具有重复username的文档。
db.users.insert( { username: "david", age: 20 } )
db.users.insert( { username: "amanda" } )
db.users.insert( { username: "rajiv", age: null } )
上一篇:唯一索引
下一篇:不区分大小写索引