Ubuntu上提升MongoDB查询速度的系统化做法
一 硬件与存储基础
- 优先使用SSD/NVMe,其随机I/O与吞吐显著优于HDD,能直接缩短查询与聚合的响应时间。
- 增加内存,MongoDB(WiredTiger)以内存映射与缓存为主,更多内存可容纳更多索引与热点数据,减少磁盘访问。
- 保障CPU与I/O余量,避免查询与后台任务争用导致抖动。
- 在Ubuntu上,MongoDB默认日志路径通常为**/var/log/mongodb/mongod.log**,慢查询(超过100ms)会默认记录,便于定位问题。
二 索引策略与查询优化
- 建立合适的索引类型:
- 单键索引:适用于单条件查询。
- 复合索引:多条件查询按使用频率与选择性排序,最多支持32个键。
- 文本索引:用于大文本的关键词匹配。
- 遵循**ESR规则(Equality, Sort, Range)**设计复合索引,使等值条件在前、排序在中、范围在后,减少排序与扫描。
- 优先实现覆盖查询(查询字段全部在索引中),并在投影中显式排除**_id或将_id**加入索引,避免回表。
- 使用explain(“executionStats”)检查是否出现COLLSCAN(全表扫描)或IXSCAN但DocsExamined/KeysExamined过大,必要时用**hint()**验证索引有效性。
- 优化字符串比较的排序规则 Collation:查询与索引的排序规则需一致才能命中索引。
- 精简返回字段(投影),减少网络与内存开销。
- 控制**$or**查询成本:为每个子句分别建立最优索引。
- 减少低效操作:避免对大文本使用无锚点的正则表达式;分页避免大偏移的skip/limit,可改用基于游标的分页。
三 配置参数与资源管理
- 存储引擎与缓存:在**/etc/mongod.conf中为WiredTiger设置storage.wiredTiger.engineConfig.cacheSizeGB**,通常将可用内存的**70%–80%**分配给MongoDB缓存(需结合系统与其他服务留出余量)。
- 连接与网络:按需调整net.maxIncomingConnections等参数,避免连接风暴与资源争用。
- 慢查询与Profiling:
- 动态设置:db.setProfilingLevel(1, 10) 记录超过10ms的操作;db.setProfilingLevel(2)记录全部。
- 日志轮转:use admin; db.runCommand({ logRotate: 1 }),便于长期分析。
- 监控:使用mongostat、mongotop观察吞吐、锁、I/O与热点集合;必要时引入PMM等第三方监控。
四 快速排查与优化清单
- 找出慢查询:
- 实时观察慢日志:tail -f /var/log/mongodb/mongod.log;
- 或在shell中开启分析:db.setProfilingLevel(1, 10),随后查询db.system.profile定位问题语句。
- 判定是否走索引:对目标语句执行 db.coll.find(…).explain(“executionStats”),关注COLLSCAN、DocsExamined/KeysExamined与是否totalDocsExamined=0(覆盖查询)。
- 优化索引:
- 依据ESR重排复合索引;
- 为排序与等值条件建立匹配索引;
- 删除不再使用或可被前缀覆盖的冗余索引;
- 对大集合的索引建立采用后台创建以减少阻塞(旧版本可用background:true)。
- 查询改写:
- 使用投影仅返回必要字段;
- 避免无索引正则与高成本**$or**;
- 分页用“上一页最大ID/时间戳”方式替代大skip。
- 配置与资源:
- 适度提升cacheSizeGB并检查页面缓存与I/O;
- 确认使用SSD、内存充足、连接数合理;
- 升级到较新的稳定版本获取性能修复与改进。
五 示例命令与配置片段
- 创建复合索引并按ESR顺序匹配查询与排序:
- db.orders.createIndex({ status: 1, createdAt: -1, price: 1 })
- 可高效支持:find({ status: “A” }).sort({ createdAt: -1 }).limit(20)
- 覆盖查询示例(排除_id或将其加入索引):
- db.posts.createIndex({ status: 1, createdAt: -1, title: 1 })
- db.posts.find({ status: “A” }, { status: 1, createdAt: 1, title: 1, _id: 0 }).explain(“executionStats”)
- 强制使用索引进行A/B验证:
- db.posts.find({ status: “A” }).hint({ status: 1, createdAt: -1 }).explain(“executionStats”)
- 配置片段(/etc/mongod.conf,示意):
- storage:
- wiredTiger:
- engineConfig:
- cacheSizeGB: <按内存70%–80%设置>
- systemLog:
- destination: file
- path: /var/log/mongodb/mongod.log
- net:
- maxIncomingConnections: <按并发调优>
- 慢查询与日志轮转:
- db.setProfilingLevel(1, 10)
- use admin; db.runCommand({ logRotate: 1 })