- Published on
Mongodb Index | 索引 相关优化 及 Mongoose 注意事项
- Authors
- Name
- Shelton Ma
1. Mongodb 索引
在 MongoDB 中,是否使用索引取决于多个因素,包括索引的类型、查询方式以及数据分布情况.
1. 否使用索引的影响因素
索引选择性:如果 查询 的值非常分散(高基数),索引会很有效.如果只有几个可能的值(低基数,例如 1-5),MongoDB 可能会直接进行 全表扫描(Collection Scan).
数据规模:对于小数据集,即使有索引,MongoDB 可能会直接扫描整个集合,而不会使用索引.
索引是否覆盖查询:
- 如果查询只涉及索引字段,MongoDB 可以 直接从索引中返回结果(覆盖索引查询,Index-Only Query).
- 如果查询还需要其他字段,MongoDB 可能需要进行 回表查询(Fetching Documents),影响查询性能.
2. 如何确认 MongoDB 是否使用了索引
使用
explain
确认查询db.collection.find({status: "deleted"}).explain() // 如果 IXSCAN(Index Scan) 出现在 stage 字段中,说明使用了索引. // 如果 COLLSCAN(Collection Scan) 出现,说明 MongoDB 没有使用索引,可能是因为索引不合适或数据量较小. db.collection.find({status: "deleted"}).explain("executionStats")
3. 复合索引的影响
在 MongoDB 中,针对多个查询条件,单独索引(单列索引) 和 联合索引(复合索引) 各有适用场景.
使用单列索引, 适用:
- 字段单独使用频率高
- 字段没有明确的查询组合模式
- 需要多个索引以供不同查询优化: 单列索引可以在查询优化时由 MongoDB 进行 索引交叉(Index Intersection),但效果不如复合索引.
- ❌ 使用组合索引查询时会有回表操作
- ❌ 占用空间
组合索引:
- 查询经常包含多个字段
- 排序优化(如果查询中 field1 过滤,field2 进行 sort,复合索引可以避免 MongoDB 进行额外的排序操作)
- 覆盖索引: 如果查询
find({ field1: 10, field2: 20 }, { field1: 1, field2: 1, _id: 0 })
,复合索引可以直接从索引返回数据,而不需要回表读取文档.
📌 **索引的“最左前缀”匹配:**索引的字段顺序很重要:
createIndex({ field1: 1, field2: 1 })
- 适用于
find({ field1: 10 })
- 适用于
find({ field1: 10, field2: 20 })
- 不适用于
find({ field2: 20 })
(因为field1
不在查询中,索引不会被高效利用)
- 适用于
4. 最佳实践
如果查询经常包含 field1 和 field2,使用复合索引
如果查询需要排序
(sort({ field2: 1 }))
,使用复合索引可直接用索引排序,而不是在内存中排序.如果使用索引排序, 索引和排序规则要一致, 比如:
db.collection.createIndex({ age: 1, score: -1 }); db.find({ age: 20 }).sort({ score: -1 })
如果 field1 和 field2 组合查询少,但 field2 需要高效查询,可以同时使用单独索引和复合索引
查询条件顺序不影响索引的使用, 查询引擎会自动优化并按照索引的顺序执行
当查询条件无法确定时, 建立单列索引方便mongodb使用
交叉索引
, 交叉索引只能用在$and
查询,$or
查询无效其他处理管理
- 定期检查索引,避免无用索引影响性能.
- 使用
createIndexes()
以手动控制索引创建 - 同步索引
await User.syncIndexes();
2. Mongoose 更新索引
1. 创建索引
userSchema.index({ age: 1 }); // 添加索引
2. Mongoose 添加索引后,已存在的 Collection 会更新吗?
如果你在已存在的 Collection 中添加索引,Mongoose 会尝试创建索引,但不会自动删除或修改已存在的索引
手动触发索引同步
await User.syncIndexes(); // 删除旧索引,并同步新的索引
生产环境需要:
- 定期检查索引,避免无用索引影响性能.
- 使用
createIndexes()
以手动控制索引创建 - 同步索引
await User.syncIndexes();
3. 聚合优化
aggregate 操作可以通过限制返回字段内容来优化性能.实际上,限制返回字段是提升 MongoDB 聚合性能的一个有效手段.具体来说,减少不必要的数据传输和处理,尤其是在聚合管道的早期阶段,能显著提高性能.