Mongodb复合索引

学习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字段,没有在该索引的前缀当中。

相关推荐
老友@41 分钟前
小集合 VS 大集合:MySQL 去重计数性能优化
数据库·mysql·性能优化
声声codeGrandMaster1 小时前
django之优化分页功能(利用参数共存及封装来实现)
数据库·后端·python·django
熏鱼的小迷弟Liu2 小时前
【Redis】Redis Zset实现原理:跳表+哈希表的精妙设计
数据库·redis·散列表
淋一遍下雨天2 小时前
Spark Streaming核心编程总结(四)
java·开发语言·数据库
zru_96023 小时前
Windows 安装 MongoDB 教程
数据库·mongodb
数据与后端架构提升之路3 小时前
深度解析如何将图像帧和音频片段特征高效存储到向量数据库 Milvus
数据库·opencv·音视频
创码小奇客4 小时前
MongoDB 事务:数据世界的守护者联盟全解析
spring boot·mongodb·trae
20242817李臻4 小时前
李臻20242817_安全文件传输系统项目报告_第9周
数据库·安全
小白考证进阶中4 小时前
0基础可以考MySQL OCP么?备考时间需要多久?
数据库·mysql·开闭原则
观无5 小时前
Redis远程链接应用案例
数据库·redis·缓存·c#