学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第90篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。
在mongodb中,为集合添加单字段索引,能够提高针对单个字段的查询效率。但对于针对多个字段的查询,要怎样提高查询效率呢?例如一个杂货店的老板,想要通过查询商品和剩余数量,来知道是否需要补货。这里我们结合官方文档,整理介绍mongodb的另一个索引类型,复合索引。
定义
复合索引是使用集合当中文档两个或多个字段构成的索引。索引中收集和排序了用户指定的字段,按照用户指定的顺序,依次分组排序。
下图展示了一个复合索引的结构。用户使用userid正序和分数倒序建立的复合索引。在mongodb索引当中,先按照userid字母表顺序正序排列,然后在每一个userid下面,分数按照倒序来排列。
在通用的查询字段上添加索引,能够增加索引覆盖查询的机会。索引覆盖查询是只能够完全使用索引来执行的查询,不需要扫描文档数据来返回结果。
语法
db.<collection>.createIndex( {
<field1>: <sortOrder>,
<field2>: <sortOrder>,
......
<fieldN>: <sortOrder>,
})
限制
- 单个复合索引,最多包含32个字段
- 索引中字段排序影响复合索引的效率。复合索引中包含了依据用户定义的字段顺序所创建的文档引用。
- 复合索引按照正序或倒序的顺序,保存指定字段值。而这种排序顺序,能够决定查询是否支持索引排序。
- 复合索引可以包含一个哈希索引字段
复合索引前缀查询
索引前缀查询表示使用索引字段中的前面部分字段来进行的索引查询。mongodb的复合索引,支持这样的前缀查询。
考虑这样的索引
{"item": 1, "location": 1, "stock": 1}
该索引当中,包含两个索引前缀
{"item": 1}
{"item": 1, "location": 1}
则该索引,能够支持下面的字段组合查询
-
- item
- item + location
- item + location + stock
mongodb也可以使用这个索引支持item + stock这两个字段的查询。但只有item字段使用了这个索引,stock查询条件无法使用这个索引。因为构建索引时, stock字段跟随在location字段后。索引数据数据中,stock字段值排列在location字段的分组中。索引字段按照建立索引时字段顺序解析。如果一个查询跳过了索引前缀,则无法使用索引。如上述索引,无法支持下面几个字段的查询
-
- location
- stock
- location + stock
缺少了item字段,这些查询都无法使用该索引。
特殊复合索引
复合索引能够包含不同类型的特殊索引。索引类型的组合方式,能够决定索引匹配文档的方式。
下面的表格展示了包含不同特殊索引的复合索引构建行为。
|------------------|------------------|
| 复合索引构成 | 复合索引行为 |
| 正序索引 倒序索引 | 为包含指定字段的文档建立索引 |
| 正序索引 倒序索引 地理位置索引 | 只能为包含地理位置的文档建立索引 |
| 正序索引 倒序索引 文本索引 | 只能为包含文档字段的文档建立索引 |
应用
构建集合students并插入数据
db.students.insertMany([
{
"name": "Alice",
"gpa": 3.6,
"location": { city: "Sacramento", state: "California" }
},
{
"name": "Bob",
"gpa": 3.2,
"location": { city: "Albany", state: "New York" }
}
])
为name字段和gpa字段添加复合索引。索引中按照name字段的正序排列,gpa字段的倒序排列
db.students.createIndex({
name: 1,
gpa: -1
})
该索引能够支持针对name和gpa两个字段的查询,也能够支持name字段的查询,因为name字段是该索引的索引前缀。
db.students.find({
name: 'Alice',
gpa: 3.6
})
db.students.find({
name: 'Bob'
})
该索引不支持仅包括gpa字段的查询,如
db.students.find({ gpa: { $gt: 3.5}})
因为gpa字段,没有在该索引的前缀当中。