Ubuntu下MongoDB索引优化技巧
user_id、电商系统的product_category。示例:db.users.createIndex({ user_id: 1 })。适用于精确匹配、范围查询(如age: { $gte: 18, $lte: 25 })或排序(如registration_date: -1)。category(选择性高于price)排序:db.products.createIndex({ category: 1, price: 1 })。也支持多字段排序,如按publish_date倒序+likes正序:db.articles.createIndex({ publish_date: -1, likes: 1 })。db.orders.createIndex({ user_id: 1, order_date: 1 }),查询user_id为"U1001"的订单日期时,指定投影{ order_date: 1, _id: 0 }即可触发覆盖。db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })(1小时后自动删除)。db.users.createIndex({ email: 1 }, { unique: true })(插入重复值会抛出E11000错误)。2dsphere索引(球面几何,适用于经纬度):db.places.createIndex({ location: "2dsphere" }),查询距离某坐标5公里内的商家:db.places.find({ location: { $near: { $geometry: { type: "Point", coordinates: [116.40, 39.90] }, $maxDistance: 5000 } } })。explain()精准分析使用explain("executionStats")查看查询执行计划,重点关注以下指标:
winningPlan:确认查询是否使用了索引(IXSCAN表示索引扫描,优于COLLSCAN全集合扫描);executionTimeMillis:查询耗时,超过100ms需优化;totalDocsExamined:扫描的文档数,若远大于返回文档数(如扫描1000文档返回10条),说明索引未生效;indexOnly:若为true,表示使用了覆盖索引(无需回表)。示例:分析db.users.find({ username: "john_doe" }).explain("executionStats"),若winningPlan为IXSCAN且indexOnly为true,则索引使用合理。
db.collection.getIndexes()查看所有索引,删除不再使用的索引(如已移除的查询字段对应的索引),示例:db.users.dropIndex({ old_field: 1 })。避免过多索引增加写操作开销(插入、更新、删除时需同步更新索引)。db.collection.reIndex()重建索引,示例:db.users.reIndex()。注意:重建期间会锁定集合,建议在低峰期操作。db.users.find({ status: "active" })需为status字段创建索引;避免在索引字段上使用函数或运算(如db.users.find({ $expr: { $gt: ["$age", 18] } })),会导致索引失效。db.users.find({ age: { $gte: 18 } }, { name: 1, age: 1, _id: 0 })(不返回_id字段,减少数据传输量)。skip()+limit()分页,但skip()在大偏移量时性能差(如skip(10000)需扫描前10000条)。替代方案:用find()的_id条件分页(如记录上一页最后一条的_id,下次查询{ _id: { $gt: last_id } })。使用MongoDB自带工具(如mongostat监控索引命中率、mongotop查看索引使用时间)或第三方工具(如Percona Monitoring and Management (PMM))实时监控索引性能。根据监控数据调整索引:如发现某索引从未被使用,及时删除;若查询模式变化(如新增了gender字段的筛选),则创建新的复合索引。