批量更新太慢了

时间:2016-09-23 05:33:57

标签: mongodb pymongo

我正在使用pymongo进行批量更新 下面的名单是一个不同的名称列表(每个名称可能在集合中有多个文档)

代码1:

bulk = db.collection.initialize_unordered_bulk_op()
for name in names:  
    bulk.find({"A":{"$exists":False},'Name':name}).update({"$set":{'B':b,'C':c,'D':d}})
print bulk.execute()  

代码2:

bulk = db.collection.initialize_unordered_bulk_op()
counter = 0
for name in names:  
    bulk.find({"A":{"$exists":False},'Name':name}).update({"$set":{'B':b,'C':c,'D':d}})
    counter =counter + 1
    if (counter % 100 == 0):
        print bulk.execute()
        bulk = db.collection.initialize_unordered_bulk_op()
if (counter % 100 != 0):
    print bulk.execute()  

我的收藏中有50000个文件。 如果我摆脱了计数器和if语句(代码1),代码就会卡住! 使用if语句(代码2),我假设这个操作不应该花费超过几分钟,但它正在采取更多的方式!你能帮助我加快速度,或者我的假设错了吗?!

1 个答案:

答案 0 :(得分:8)

您很可能忘记添加索引来支持您的查询! 这将触发每个操作的完整收集扫描,这很慢(正如您所知)。

以下代码使用update_many进行测试,并且在'name'和'A'字段中没有和带索引的批量内容。你得到的数字不言自明。

备注,我没有足够的热情为50000做这个没有索引但是10000文件。 10000的结果是:

  • 没有索引和update_many:38.6秒
  • 没有索引和批量更新:28.7秒
  • with index和update_many:3.9秒
  • 索引和批量更新:0.52秒

对于添加了索引的50000文档,需要2.67秒。我确实在Windows机器上运行了测试,而mongo在docker中的同一主机上运行。

有关索引的详细信息,请参阅https://docs.mongodb.com/manual/indexes/#indexes。简而言之:索引保存在RAM中,允许快速查询和查找文档。索引必须专门选择匹配您的查询。

from pymongo import MongoClient
import random
from timeit import timeit


col = MongoClient()['test']['test']

col.drop() # erase all documents in collection 'test'
docs = []

# initialize 10000 documents use a random number between 0 and 1 converted 
# to a string as name. For the documents with a name > 0.5 add the key A
for i in range(0, 10000):
    number = random.random()
    if number > 0.5:
        doc = {'name': str(number),
        'A': True}
    else:
        doc = {'name': str(number)}
    docs.append(doc)

col.insert_many(docs) # insert all documents into the collection
names = col.distinct('name') # get all distinct values for the key name from the collection


def update_with_update_many():
    for name in names:
        col.update_many({'A': {'$exists': False}, 'Name': name},
                        {'$set': {'B': 1, 'C': 2, 'D': 3}})

def update_with_bulk():
    bulk = col.initialize_unordered_bulk_op()
    for name in names:
        bulk.find({'A': {'$exists': False}, 'Name': name}).\
            update({'$set': {'B': 1, 'C': 2, 'D': 3}})
    bulk.execute()

print(timeit(update_with_update_many, number=1))
print(timeit(update_with_bulk, number=1))
col.create_index('A') # this adds an index on key A
col.create_index('Name') # this adds an index on key Name
print(timeit(update_with_update_many, number=1))
print(timeit(update_with_bulk, number=1))