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

相关推荐
AOwhisky8 小时前
MySQL 学习笔记(第四期):SQL 语言之多表查询
linux·运维·网络·数据库·笔记·学习·mysql
小红卒8 小时前
mysql之udf提权
数据库·mysql·网络安全
Trouvaille ~8 小时前
【Redis篇】Redis 哨兵(Sentinel):高可用自动故障转移
数据库·redis·缓存·中间件·sentinel·高可用·哨兵
qfljg8 小时前
oracle 迁移到postgres
数据库·oracle
giaz14n9X9 小时前
Redis 分布式锁进阶第五十七篇
数据库·redis·分布式
剑神一笑9 小时前
Linux ls 命令深度解析:从目录遍历到颜色输出的实现原理
linux·服务器·数据库
Maynor9969 小时前
Codex API 网关迁移与流量优化实战
数据库·oracle
WyCAGy8ij10 小时前
Redis 分布式锁进阶第二篇讲解
数据库·redis·分布式
南极企鹅10 小时前
MySQL的两大支柱:undo Log&redo log
数据库·mysql·oracle
智航GIS10 小时前
ArcGIS大师之路500技---078文件数据库的加密与解密
数据库·arcgis