应改用countdocuments()或estimateddocumentcount()替代已弃用的count():前者需匹配查询条件的复合索引,后者直接读元数据、毫秒返回但无条件支持。

count() 会全表扫描,别用它
面对 2000 万级集合,count() 默认不走索引,哪怕你加了索引,它仍可能扫描全部文档——因为它的实现逻辑是遍历 cursor 并累加。实测中,db.collection.count({status: "active"}) 在无索引时耗时数秒;即使加了 {status: 1} 索引,count() 也常忽略索引,直接走 collection scan。
- 这是 MongoDB 旧版驱动和 shell 的默认行为,不是 bug,而是设计选择
-
count()已在 4.0+ 版本中标记为 deprecated,官方明确建议迁移到countDocuments()或estimatedDocumentCount() - 如果你在 Spring Data MongoDB 中用
MongoTemplate.count(),底层调用的仍是count(),需显式切换
用 countDocuments() + 合理索引才真正生效
countDocuments() 是带条件计数的正确姿势,但它**必须配合能覆盖查询条件的索引**,否则照样慢。关键不是“有没有索引”,而是“索引能不能让 IXSCAN 直接命中过滤条件”。
- 单字段查询(如
{type: "order"}):建{type: 1}即可 - 多字段 AND 查询(如
{type: "order", status: "paid"}):优先按 ESR 规则建复合索引 ——{type: 1, status: 1},而非两个单字段索引 - 含范围查询(如
{created_at: {$gte: ISODate("...")}, status: "done"}):把等值字段放前,范围字段放后 ——{status: 1, created_at: 1},否则created_at无法被索引高效利用 - 避免在索引字段上用
$in多值(尤其 > 5 个),MongoDB 对$in的索引使用效率会断崖下降;可拆成多个countDocuments()并行调用
estimatedDocumentCount() 不走索引但快得离谱
如果你只需要“大概有多少条”,比如做分页总条数显示、后台统计概览,estimatedDocumentCount() 是唯一能毫秒返回的答案。它读的是集合元数据里的 count 字段,完全不碰实际文档。
- 执行
db.collection.estimatedDocumentCount()永远是 O(1),无论集合 200 万还是 2 亿 - 结果不实时:CRUD 操作后,该值可能滞后几秒(取决于存储引擎刷新频率),但对大多数展示类场景足够准确
- 不能带查询条件 —— 它只返回整个集合的估算总数;要带条件估算?没原生支持,只能靠采样或预聚合
- 注意:副本集主节点和从节点的估算值可能短暂不一致,读取时指定
readPreference: "primary"
聚合管道里 count 别乱写 $group
有人想用 aggregate([...{$group: {_id: null, cnt: {$sum: 1}}}] 替代 countDocuments(),这反而更慢。聚合框架的 $group 必须把所有匹配文档拉进内存再累加,IO 和 CPU 开销远高于优化过的 countDocuments()。
- 仅当你要同时做筛选 + 分组 + 计数(如按状态分组统计)时,才用聚合;纯计数,别绕路
- 如果非要用聚合,确保
$match是第一个 stage,且该 stage 能命中索引 —— 查看explain()输出中"stage": "IXSCAN"和"docsExamined"是否接近"nReturned" -
$group阶段没有索引概念,它只消费上游输出;上游没过滤干净,它就得处理全部中间结果 - 聚合中
$limit对$group计数无效 —— 它只限制最终输出条数,不影响计数逻辑
count(),等于白干。











