Skip to content

索引类型与结构

MongoDB 常规单字段和复合索引使用有序 B-tree 结构。索引保存 Field Value 与 Record Location,用于缩小文档扫描范围或直接提供排序;索引不会自动改善与其键顺序、类型或操作符不匹配的查询。


索引类型

类型用途主要边界
Single Field单字段过滤和排序复合条件可能需要额外过滤
Compound多字段过滤、排序和覆盖查询字段顺序决定可用前缀与排序能力
Multikey自动索引数组中的元素一个复合索引中每个文档不能有多个被索引的数组字段
Unique约束不同文档间键值唯一缺失和 null 的行为需结合 Sparse/Partial 设计
Partial只索引满足表达式的文档查询必须包含能够使用该过滤条件的语义
Sparse只索引包含目标 Field 的文档null、缺失和唯一性组合时容易混淆
TTL到期后由后台任务删除文档删除不是精确到期瞬间,不适合严格调度
Wildcard索引变化或未知的 Field Path不能替代面向真实负载的专用索引
Text自托管全文词项检索功能和语言处理有限,与 Atlas Search 不同
2d / 2dsphere平面或 GeoJSON 地理查询坐标格式和支持操作符不同
Hashed支持哈希分片和等值分布不保留范围顺序
Clustered Collection按 Clustered Key 组织记录与普通 Secondary Index 的物理语义不同

复合索引顺序

常用思路是 ESR:Equality、Sort、Range,但它是启发式规则,不是机械公式。

javascript
db.orders.createIndex({ tenantId: 1, status: 1, createdAt: -1 })

该索引适合固定 tenantIdstatus 后按 createdAt 倒序读取。仅查询 status 通常不能有效使用最左前缀;对 createdAt 使用范围后,后续键能否继续缩小扫描也会受到限制。

复合索引的升降序只有在支持排序时才真正重要。查询能够按索引整体方向或整体反向扫描,但混合排序方向必须与索引键方向匹配。


Multikey

对数组 Field 建索引后会自动成为 Multikey Index,一个文档可能为多个数组元素生成索引项:

javascript
db.users.createIndex({ tags: 1 })

数组越长,索引写入、空间和扫描成本越高。查询同一个数组元素内的多个约束时,通常需要 $elemMatch 让语义和 Index Bound 正确组合。


Covered Query

如果 Filter 和 Projection 所需字段都能从索引获得,执行计划可能无需读取完整文档。是否覆盖还受 _id 是否被返回、Multikey 路径、字段存在性和具体查询操作符影响。

覆盖索引会减少文档读取,但把过多 Field 加入索引会扩大 Cache 占用和写放大。索引设计应围绕稳定高频查询,而不是为每个字段都建立索引。


执行计划与维护

javascript
db.orders.find({ tenantId: 1, status: "paid" })
  .sort({ createdAt: -1 })
  .explain("executionStats")

重点观察:

  • winningPlanIXSCANCOLLSCAN 还是需要阻塞排序。
  • totalKeysExaminedtotalDocsExamined 相对返回数量是否过大。
  • 是否存在 FETCH 后过滤大量文档。
  • Plan Cache 是否因数据分布变化保留了不合适计划。
  • 重复或前缀包含的索引能否合并,删除前是否覆盖完整业务周期。

Index Build、隐藏、删除和 Compact 等维护动作会消耗 CPU、I/O、内存及复制带宽,需要按版本能力和业务窗口规划。

参考资料