MongoDB入门学习教程,从入门到精通,MongoDB索引(5)

MongoDB索引

一、索引简介

1.1 索引的概念
  • 索引 是一种特殊的数据结构,存储在内存中,用于提高查询效率。
  • MongoDB 中索引使用 B-Tree 结构(默认),支持高效的范围查询和排序。
  • 索引类似于书籍的目录,能快速定位到数据所在位置,避免全表扫描。
1.2 索引的作用
  • 加速查询:尤其是对大量数据的查询、排序、分组等操作。
  • 唯一性约束:通过唯一索引保证字段值不重复。
  • 覆盖查询:当查询的字段全部在索引中时,可以直接从索引返回结果,无需访问文档。
1.3 索引的代价
  • 占用存储空间:每个索引都会占用额外的磁盘和内存空间。
  • 影响写入性能:插入、更新、删除操作时,需要同步维护索引,导致写操作变慢。
  • 增加内存压力:索引应尽量常驻内存,否则会影响性能。

二、explain输出

2.1 explain() 方法
  • 用于分析查询的执行计划,帮助判断查询是否使用了索引。
  • 语法:db.collection.find().explain("executionStats")
2.2 explain 的三种模式
模式 说明
queryPlanner 只返回查询计划,不实际执行
executionStats 返回查询计划并执行,显示执行统计信息
allPlansExecution 返回所有候选执行计划的详细信息
2.3 关键输出字段解读
字段 含义
stage 执行阶段,如 COLLSCAN(全表扫描)、IXSCAN(索引扫描)、FETCH(回表读取文档)
nReturned 返回的文档数量
totalDocsExamined 扫描的文档总数
totalKeysExamined 扫描的索引条目数
indexName 使用的索引名称
winningPlan 最终选择的执行计划
2.4 性能分析原则
  • 理想情况totalKeysExamined ≈ nReturned,且使用 IXSCAN
  • 需优化情况totalDocsExamined 远大于 nReturned,说明未有效使用索引。

三、何时不使用索引

3.1 不适合使用索引的场景
场景 原因
集合很小 全表扫描比索引查找更快,索引反而增加开销
查询返回大部分数据 索引+回表可能比全表扫描更慢
频繁更新的字段 索引维护成本高
低基数字段 如性别、布尔值等,索引区分度低,效率提升有限
查询使用正则表达式(非前缀) /.*abc/ 无法利用索引
大量写操作场景 索引会显著降低写入性能
3.2 如何判断是否使用索引
  • 使用 explain() 分析执行计划。
  • 如果 stageCOLLSCAN,说明未使用索引。
  • 结合业务读写比例,权衡是否建立索引。

四、索引类型

4.1 单字段索引
  • 最基础的索引类型,针对单个字段建立。
  • 示例:db.users.createIndex({name: 1})
4.2 复合索引
  • 针对多个字段建立的索引,顺序非常重要。
  • 遵循 ESR 原则:等值查询(Equality) → 排序字段(Sort) → 范围查询(Range)
  • 示例:db.users.createIndex({age: 1, name: -1})
4.3 多键索引
  • 用于数组字段,MongoDB 自动为数组每个元素创建索引。
  • 示例:db.articles.createIndex({tags: 1})
4.4 唯一索引
  • 确保字段值唯一,不允许重复。
  • 示例:db.users.createIndex({email: 1}, {unique: true})
4.5 稀疏索引
  • 只索引包含该字段的文档,适用于字段缺失较多的集合。
  • 示例:db.users.createIndex({email: 1}, {sparse: true})
4.6 文本索引
  • 支持字符串内容的全文检索,可对多个字段建立。
  • 示例:db.articles.createIndex({content: "text", title: "text"})
4.7 地理空间索引
  • 支持地理坐标查询,如 2dsphere(球面)和 2d(平面)。
  • 示例:db.places.createIndex({location: "2dsphere"})
4.8 哈希索引
  • 用于分片键,支持等值查询,不支持范围查询。
  • 示例:db.users.createIndex({user_id: "hashed"})
4.9 TTL索引
  • 自动删除过期文档,常用于日志、会话数据。
  • 示例:db.sessions.createIndex({createdAt: 1}, {expireAfterSeconds: 3600})

五、索引管理

5.1 创建索引
javascript 复制代码
// 单字段索引
db.collection.createIndex({field: 1})

// 复合索引
db.collection.createIndex({field1: 1, field2: -1})

// 带选项的索引
db.collection.createIndex({field: 1}, {unique: true, background: true})
5.2 查看索引
javascript 复制代码
// 查看集合所有索引
db.collection.getIndexes()

// 查看索引大小
db.collection.stats().indexSizes
5.3 删除索引
javascript 复制代码
// 删除指定索引
db.collection.dropIndex("index_name")

// 删除所有非 _id 索引
db.collection.dropIndexes()
5.4 索引构建方式
方式 说明
background: true 后台构建,不阻塞读写,但速度较慢(早期版本)
默认(前台) 阻塞所有读写操作,适合维护窗口执行
滚动索引构建 在副本集中逐个节点构建,减少影响
5.5 索引优化建议
  • 避免冗余索引 :如已有 {a:1, b:1},则 {a:1} 是冗余的。
  • 使用覆盖查询 :尽量让查询字段全部在索引中,避免 FETCH
  • 监控索引使用情况 :通过 $indexStatsexplain() 分析未使用的索引。
  • 定期重建索引:对于频繁更新的集合,索引碎片可能影响性能。

总结

MongoDB 索引是提升查询性能的关键工具,但并非所有场景都适合使用。合理设计索引需要结合查询模式、数据分布、读写比例等因素。通过 explain() 分析执行计划、选择合适的索引类型、科学管理索引生命周期,可以有效平衡查询性能与系统开销。

相关推荐
悠哉悠哉愿意8 小时前
【物联网学习笔记】TIM
笔记·单片机·嵌入式硬件·物联网·学习
2401_835956818 小时前
如何利用SQL子查询进行实时监控数据分析_性能优化
jvm·数据库·python
一只大袋鼠8 小时前
Java JDBC 封装:从原生写法到工具类封装 + 增删改查
java·开发语言·数据库·mysql
a9511416428 小时前
如何在Bootstrap中实现响应式的统计数据卡片
jvm·数据库·python
熬夜的咕噜猫8 小时前
Nosql Redis配置与优化
数据库·redis·nosql
椰猫子8 小时前
数据库(数据库相关概念、MySQL数据库、SQL(DDL、DML、DQL))
数据库·sql·mysql
Shorasul8 小时前
golang如何实现设备数据采集网关_golang设备数据采集网关实现要点
jvm·数据库·python
2301_764150568 小时前
如何用 some 检测数组中是否存在至少一个满足条件的项
jvm·数据库·python
j_xxx404_8 小时前
数据库基础夯实:从零手写DDL与DML,MySQL核心语法实战解析
数据库·mysql
爱学习的小囧8 小时前
VMware NSX-T Data Center 3.2.3.0 部署后账号密码获取及登录配置教程
linux·运维·服务器·网络·数据库·esxi