对MongoDB实例中的每个文档执行操作

2024-02-26 10:58:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个包含150万个文档的mongoDB集合,所有文档都有相同的字段,我想获取字段a的内容(在每个文档中都是唯一的)并对其执行f(A),然后创建并填充字段B。Python中的伪代码:

for i in collection.find():
    x = i**2
    collection.update(i,x) #update i with x

注意:我知道更新代码可能是错误的,但除非它影响操作速度,否则为了简单起见,我选择将其保留在那里

问题是,这段代码真的很慢,主要是因为它可以在大约一秒钟内运行1000个文档,然后服务器关闭光标大约一分钟,然后再允许1000个。我想知道是否有任何方法来优化这个操作,或者我是否被这个缓慢的瓶颈困住了

附加说明:

  1. 我调整了batch_size作为一个实验,它更快,但效率不高,仍然需要几个小时

  2. 我也知道SQL可能会更快地完成这项工作,我使用noSQL数据库的其他原因与此问题无关

  3. 实例正在本地运行,因此无论出于何种目的,都没有网络延迟

  4. 我看过this问题,但它的答案并不能真正解决我的问题


Tags: 方法代码in文档服务器内容formongodb
2条回答

数据库客户机往往从实际的数据库活动中抽象出来,因此观察到的延迟行为可能具有欺骗性。很可能您在这段时间内确实在敲打数据库,但是Python解释器对活动是完全隐藏的

也就是说,你可以做一些事情让它更轻

1)在更新所基于的属性A上建立索引。这将使它更快地返回

2)在您的find调用中放置一个投影操作符:

for doc in collection.find(projection=['A']):

这将确保您只返回需要返回的字段,并且如果您正确地索引了unique A属性,将确保您的结果完全来自非常快速的索引

3)使用update操作符确保只需将新字段发送回。与其发送整个文档,不如发回字典:

{'$set': {'B': a**2}}

它将在每个文档中创建字段B,而不影响任何其他内容

所以,整个街区看起来是这样的:

for doc in collection.find(projection=['A', '_id']):
    collection.update(filter={'_id': doc['_id']},
                      update={'$set': {'B': doc['A']**2}})

这将大大减少Mongo必须做的工作,以及(目前与您无关的)网络流量

也许你应该在多个线程中进行更新。我认为最好是在一个线程中加载数据,将其分成多个部分,然后将这些部分传递给将执行更新的并行工作线程。它会更快

编辑:

我建议你做分页查询。 Python伪代码:

count = collection.count()
page_size = 20
i = 0;
while(i < count):
    for row in collection.find().limit(pageSize).skip(i):
        x = i**2
        collection.update(i, x);
    i += page_size

相关问题 更多 >