2016-09-23 38 views
6

我正在使用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),我假设这个操作不应该花费几分钟的时间,但是它比这个更多!你能帮我把它变快吗?还是我错了我的假设?!

回答

6

你很可能忘了添加索引来支持你的查询! 这将触发完整的收集扫描你的每一个操作是无聊的慢(如你所知道的)。

以下代码使用update_many进行测试,并且在'名称'和'A'字段中使用不带索引和带索引的批量填充。你得到的数字是为自己说话的。

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

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

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

有关索引的更多信息,请参阅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)) 
+0

感谢您的帮助,但我认为您在上面给出的时间点不正确,因为它们不是10000个文件,但只有一半(考虑> 0.5和<= 0.5是平等的可能)。此外,如果您可以分享如何为初学者编制字段A和名称的索引,这将有所帮助。再次感谢! – amazingCodingExperience

+0

另外,如何索引固定过程?你能分享一下这个理论吗? – amazingCodingExperience

+0

添加更多信息给我的答案。但是,mongodb免费提供相当不错的在线课程:https://university.mongodb.com/courses/M101P/about我建议你选择其中的一种来加速mongo。 – squanto773