count、countDocuments、estimatedDocumentCount 到底差在哪?各自执行什么?哪个会不准?这篇在 100 万个文档上量耗时、看 explain,还试了 kill -9 之后的计数。
estimatedDocumentCount() 0.2 ms = 1,000,000
count_documents({}) 97 ms = 1,000,000
count_documents({a: 5})(a 有索引) 1.4 ms = 10,000
count_documents({b: 5})(b 无索引) 110 ms = 1,000
命令 count({})(旧) 0.5 ms = 1,000,000
命令 count({a: 5})(旧) 1.7 ms = 10,000estimatedDocumentCount 读集合元数据,0.2 ms;countDocuments({}) 要数全部文档,97 ms;带条件的 countDocuments 取决于有没有索引(1.4 ms 对 110 ms)。
test> db.t.explain().count({a: 5})
{ stage: 'COUNT', input: 'COUNT_SCAN' }
test> db.t.explain().count({})
{ stage: 'RECORD_STORE_FAST_COUNT', fast: undefined }
test> countDocuments({a: 5}) 内部是 aggregate [{$match: {a: 5}}, {$group: {_id: 1, n: {$sum: 1}}}]
{
plan: 'GROUP > COUNT_SCAN(a_1)',
nReturned: 1,
keysExamined: 10000,
docsExamined: 0,
ms: 1
}
test> countDocuments({b: 5}) 内部的 aggregate
{
plan: 'GROUP > COLLSCAN',
nReturned: 1,
keysExamined: 0,
docsExamined: 1000000,
ms: 121
}
test> $collStats {count: {}}
[
{
ns: 'test.t',
host: 'host1:9901',
localTime: ISODate('2026-10-12T02:44:31.115Z'),
count: 1000000
}
]旧 count 命令不带条件是 RECORD_STORE_FAST_COUNT;countDocuments 内部是 aggregate,有索引时 GROUP > COUNT_SCAN,没有就 GROUP > COLLSCAN。
SIGKILL 之前:estimatedDocumentCount = 300,000,countDocuments = 300,000 重启之后:estimatedDocumentCount = 0,countDocuments = 298,500 validate 之后:estimatedDocumentCount = 298,500(validate 返回 nrecords = 298,500)
元数据计数在 kill -9 后重启时是 0,对集合做 validate 才修正;countDocuments 不受影响。(本实验里是新建集合、没有经历过 checkpoint 的情形。)
delete_many({a: {$lt: 50}}) 之后:estimatedDocumentCount = 500,000,countDocuments = 500,000正常运行时,删除大量文档后元数据计数立即更新。
count_documents({}, limit=1000):0.4 ms;不带 limit:51 ms
count_documents({a: 60}, limit=1000):0.5 ms;不带 limit:1.6 ms
test> db.t.distinct("a").length // a 有索引
50
distinct("a") 耗时 0.6 ms;distinct("b")(无索引)耗时 120 mscountDocuments 带 limit 数到上限就停;distinct 在有索引的字段上也很快(0.6 ms)。
test> db.t.count() // mongosh 旧方法
DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.
500000
test> db.t.count({a: 60})
DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.
10000总数用 estimatedDocumentCount,带条件的精确值用 countDocuments;旧的 count() 已弃用。