【MongoDB】索引属性 之 局部索引(Partial Indexes)

本章内容:

  • 创建局部索引
  • 行为
  • 限制条件
  • 例子

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 } )

上一篇:唯一索引

下一篇:不区分大小写索引

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值