MongoDB 索引策略在 Ubuntu 上的选择
一 核心原则与索引类型
- 索引选择以查询模式为核心,优先为高频出现在查询条件、排序、聚合中的字段建立索引;权衡读写比例、字段基数与索引维护成本。
- 常用索引类型与适用场景如下:
| 索引类型 |
适用场景 |
关键要点 |
| 单字段索引 |
单一条件查询 |
语法:{field: 1} 或 {field: -1} |
| 复合索引 |
多条件查询 + 排序 |
顺序敏感,遵循前缀匹配;可用作“最左前缀”查询 |
| 多键索引 |
数组字段查询 |
对数组元素自动建立多键索引 |
| 文本索引 |
字符串全文检索 |
使用 {field: “text”};支持权重等选项 |
| 地理空间索引 |
地理位置查询 |
2d(平面)/ 2dsphere(球面) |
| 哈希索引 |
等值查询、哈希分片 |
使用 {field: “hashed”},仅支持等值匹配 |
| TTL 索引 |
自动过期数据 |
{createdAt: 1}, {expireAfterSeconds: N} |
| 部分索引 |
条件子集高频查询 |
仅对满足条件的文档建索引,减小体积 |
| 稀疏索引 |
字段并非所有文档都有 |
仅索引包含该字段的文档 |
上述类型与特性为 MongoDB 官方索引类型范畴,适用于 Ubuntu 上的自托管部署;具体选择仍取决于业务查询与数据特征。
二 复合索引设计与查询匹配规则
- 采用 ESR 规则(等值 → 排序 → 范围) 安排复合索引字段顺序:
例:查询 {a: 1, b: 2, c: {$gte: 1}}.sort({d: 1, e: -1}),可优先设计索引:{a: 1, b: 1, d: 1, e: -1, c: 1}。
- 索引前缀原则:复合索引可支持“最左前缀”查询,如索引 {a:1, b:1, c:1} 可覆盖 {a:…}、{a:…, b:…},但不覆盖 {b:…, c:…}。
- 排序与范围位置:若查询包含排序,尽量让排序字段位于索引中且位于范围条件之前;避免在范围条件后再排序。
- 覆盖索引:将查询所需字段全部放入索引(必要时显式包含或排除 _id),可使查询仅扫描索引、无需回表,降低 IO。
- 低基数字段谨慎:如“性别、状态”等值分布极少,索引选择性低,收益有限且增加维护成本。
- 谨慎使用会削弱索引的操作符:如 $ne、$nin、$not、$mod 等,易导致扫描或无法有效利用索引。
三 Ubuntu 上的实施步骤与常用命令
- 连接与基础操作
- 连接 Shell:mongo(或 mongosh)
- 创建索引:db.collection.createIndex({field: 1});后台创建:{background: true};唯一索引:{unique: true}
- 查看索引:db.collection.getIndexes();删除索引:db.collection.dropIndex({field: 1}) 或按名称删除
- 查询分析与验证
- 执行计划:db.collection.find({…}).explain(“executionStats”),关注 stage 是否为 IXSCAN、是否出现 SORT/MERGE_SORT、以及 keysExamined 与 nReturned 的比例
- 索引使用统计:在聚合中使用 $indexStats 阶段,识别未使用或低效索引
- 维护与监控
- 碎片与重建:db.collection.reIndex()(谨慎,生产建议低峰期执行)
- 资源监控:使用 mongostat、mongotop 观察索引命中与操作耗时;必要时结合 PMM 等第三方监控
- 配置层面(/etc/mongod.conf)
- 适度调整 WiredTiger 缓存:storage.wiredTiger.engineConfig.cacheSizeGB(如可用内存的 70%–80% 分配给 MongoDB)
- 慢查询与连接:开启 profiling 监控慢查询,合理设置 net.maxIncomingConnections 等网络参数
以上命令与路径为 Ubuntu 上常见做法;索引创建、explain 与索引维护语法为 MongoDB 通用接口。
四 场景化索引方案示例
- 用户登录与唯一约束:db.users.createIndex({email: 1}, {unique: true});高频登录建议再为 {username: 1} 建立索引。
- 时间范围 + 状态筛选 + 排序分页:db.orders.createIndex({status: 1, createdAt: -1, _id: -1}),配合 .limit(N).skip(M) 实现高效分页。
- 全文搜索:db.posts.createIndex({title: “text”, content: “text”}, {weights: {title: 10, content: 1}})。
- 地理位置附近查询:db.places.createIndex({location: “2dsphere”})。
- 会话/日志自动过期:db.sessions.createIndex({lastActive: 1}, {expireAfterSeconds: 3600})。
- 数组标签查询:db.articles.createIndex({tags: 1})(自动多键);若需去重计数可结合聚合。
- 分片键等值查询:db.events.createIndex({shardKey: “hashed”})(用于哈希分片场景)。
五 常见陷阱与优化要点
- 避免“过度索引”:每增加一个索引都会增加写放大与存储占用,定期清理未使用或低使用率索引。
- 避免低效查询模式:在条件中使用 $ne/$nin/$not/$mod、对索引字段做算术/正则不匹配等,常导致无法命中索引或性能退化。
- 控制索引规模与内存:索引应尽量能驻留内存;通过 db.collection.totalIndexSize() 与集合统计评估索引体积,必要时精简或重构索引。
- 必要时使用 hint() 进行索引验证:在测试环境强制指定候选索引,配合 explain 验证执行计划与成本,再决定是否保留或调整。
- 分片集群注意:分片键是最重要的索引之一;哈希分片使用 hashed 索引,范围分片需结合查询范围设计。
以上要点有助于在 Ubuntu 上长期保持索引策略的有效性与可维护性。