聚合查询慢的主因是mongos与shard跨机房导致网络延迟叠加,需确保同机房部署、shard key与索引对齐、禁用链式复制,并验证聚合阶段是否下推至shard执行。

聚合查询慢,先看mongos和shard是否跨机房
聚合操作本身不重,但mongos必须把$match、$sort等阶段下推到shard执行,再汇总结果。如果mongos和某个shard之间RTT超过10ms(比如部署在不同城市或云厂商可用区),一次聚合就可能多耗50–200ms——尤其当管道含多个stage、涉及多个shard时,延迟会叠加。这不是代码写得不好,是网络拓扑硬伤。
实操建议:
- 所有
mongos进程必须与config server同机房,且优先靠近主shard集群(通常也是业务入口所在机房) - 每个shard replica set的Primary应固定在主中心机房(通过
members[n].priority设为2,其他机房节点设为1) - 禁用链式复制:
settings.chainingAllowed: false,防止secondary从远端secondary同步,放大延迟 - 用
db.runCommand({ "connPoolStats": 1 })检查mongos到各shard的平均连接延迟(字段avgPingMs),>15ms即需调整
聚合阶段无法下推?检查shard key与索引对齐
如果$match字段不是shard key前缀,或没在shard上建对应索引,mongos只能拉全量数据回本地聚合,网络流量和延迟直接翻倍。常见于按时间范围+用户ID聚合,但shard key是{region: 1, userId: 1},而查询只用了createdAt。
实操建议:
- 确认聚合中首个
$match条件字段是否为shard key的左前缀;否则改用shard key + 过滤字段建复合索引 - 在目标shard上手动执行相同聚合管道,加
{explain: true},看executionStages.stage是否含SHARDING_FILTER——没有说明未下推 - 避免在
$lookup中跨shard关联:被关联集合也必须分片,且join字段需是shard key,否则触发广播查询
读偏好设置不当,导致聚合总走远端secondary
默认readPreference=primary,但如果Primary在远机房,而本地secondary有最新oplog(optimeDate差secondaryPreferred,聚合仍强制走远端。
实操建议:
- 应用连接串显式指定
?readPreference=primaryPreferred&readPreferenceTags=region:A,标签匹配主中心 - 在shard replica set中给主中心节点打tag:
{"region": "A"},非主中心节点votes: 0且priority: 0 - 聚合前加
$addFields: { _ts: "$$NOW" }并配合readConcern: "majority",可规避因secondary数据陈旧导致的重复拉取
config server路由表过期引发聚合错路
当mongos与config server跨机房,网络抖动会导致mongos缓存的chunk分布信息stale。聚合时可能把本该发往shard-A的请求错发到shard-B,后者返回ShardKeyNotFound或空结果,mongos再重试,延迟翻倍。
实操建议:
- 用
db.printShardingStatus()检查config version是否持续更新;若停滞,立刻查config server日志中是否有Waiting for majority commit -
mongos配置中调大refreshLogicalSessionCacheRefreshMinutes(默认30),但更关键是确保其与config server同机房 - 禁止在聚合管道中动态计算shard key值(如
$dateToString后用于$match),这会让路由决策失败,强制广播
mongos部署位置和config server强绑定关系——哪怕其他所有参数都调优了,只要mongos在B机房而config server在A机房,聚合延迟就永远有不可控的基线抖动。

















