为什么 PyMongo count_documents 比计数慢?

Why is PyMongo count_documents is slower than count?

db['TF'] 我有大约 6000 万条记录。

我需要获取记录的数量。

如果我运行db['TF'].count(),马上returns。

如果我运行db['TF'].count_documents({}),那么我得到结果需要很长时间。

但是,count 方法将被弃用。

那么,如何在使用count_documents时快速获取数量呢?有没有我遗漏的论据?

我已经阅读了文档和代码,但没有找到。

非常感谢!

这不是关于 PyMongo 而是 Mongo 本身。

count 是原生的 Mongo 函数。它并没有真正计算所有文件。每当您在 Mongo 中插入或删除一条记录时,它都会缓存集合中的记录总数。然后当你 运行 count 时,Mongo 将 return 该缓存值。

count_documents 使用查询对象,这意味着它必须遍历所有记录才能获得总计数。因为您没有传递任何参数,所以它必须 运行 超过所有 6000 万条记录。这就是它慢的原因。

基于@Stennie 评论

You can use estimated_document_count() in PyMongo 3.7+ to return the fast count based on collection metadata. The original count() was deprecated because the behaviour differed (estimated vs actual count) based on whether query criteria was provided. The newer driver API is more intentional about the outcome

如前所述,该行为并非特定于 PyMongo。

原因是因为 count_documents method in PyMongo performs an aggregation query and does not use any metadata. see collection.py#L1670-L1688

pipeline = [{'$match': filter}]
if 'skip' in kwargs:
    pipeline.append({'$skip': kwargs.pop('skip')})
if 'limit' in kwargs:
    pipeline.append({'$limit': kwargs.pop('limit')})
pipeline.append({'$group': {'_id': None, 'n': {'$sum': 1}}})
cmd = SON([('aggregate', self.__name),
           ('pipeline', pipeline),
           ('cursor', {})])
if "hint" in kwargs and not isinstance(kwargs["hint"], string_type):
    kwargs["hint"] = helpers._index_document(kwargs["hint"])
collation = validate_collation_or_none(kwargs.pop('collation', None))
cmd.update(kwargs)
with self._socket_for_reads(session) as (sock_info, slave_ok):
    result = self._aggregate_one_result(
        sock_info, slave_ok, cmd, collation, session)
if not result:
    return 0
return result['n']

此命令具有相同的 behavior as the collection.countDocuments 方法。

话虽如此,如果您愿意用准确性换取性能,您可以使用 estimated_document_count method which on the other hand, send a count command to the database with the same behavior as collection.estimatedDocumentCount See collection.py#L1609-L1614

if 'session' in kwargs:
    raise ConfigurationError(
        'estimated_document_count does not support sessions')
    cmd = SON([('count', self.__name)])
    cmd.update(kwargs)
    return self._count(cmd)

其中 self._count 是助手 发送命令。