【问题标题】:Slow Upserts with PyMongoDB使用 MongoDB 减缓 Upserts
【发布时间】:2014-07-03 23:40:47
【问题描述】:

我正在尝试在没有多线程的 macbook air 1.7GHz i7 上使用 PyMongo 将大约 8 亿条记录插入 MongoDB,文档的结构如下:

我正在阅读的记录是以下元组:

(user_id,imp_date,imp_creative,imp_pid,geo_id)

我正在根据正在读取的文件中的 user_id 创建自己的 _id 字段。

{_id:user_id,
'imp_date':[array of dates],
'imp_creative':[array of numeric ids],
'imp_pid':[array of numeric ids],
'geo_id':numeric id}

我正在使用带有 $push 的 upsert 来为相应的数组附加日期、广告 ID 和 pid

self.collection.update({'_id':uid},
                       {"$push":{'imp_date':<datevalue>,
                                 'imp_creative':<creative_id>,
                                 'imp_pid':<pid>}},safe=True,upsert=True)

我正在使用带有 $set 的 upsert 来覆盖地理位置(只关心最近的。

self.collection.update({'_id':uid},
                       {"$set":{'geo_id':<geo id>}},safe=True,upsert=True)

我每秒只写大约 1,500 条记录(如果我设置 safe=False,则为 8,000 条)。我的问题是:我该怎么做才能进一步加快速度(理想情况下是 20k/秒或更快)?

我找不到关于以下方面的明确建议的想法: - 使用多线程插入数据 -分片 -填充数组(我的数组增长非常缓慢,每个文档数组在文件末尾的平均长度约为 4) -关闭日记功能

抱歉,如果我遗漏了任何必要的信息,这是我的第一篇文章。

【问题讨论】:

  • 恩里克在他的回答中有一些很好的建议。您是否也尝试过拆分批处理并在两个单独的连接/机器上运行它?我只是做了一个基本的测试,似乎这两个连接并没有减慢对方的速度。换句话说,线程可能会对您产生最显着的影响。

标签: mongodb pymongo


【解决方案1】:

1- 你可以添加一个索引来加速它,索引会帮助你更快地找到文档,尽管插入会更慢(你也必须更新索引)。检索阶段的改进是否补偿了更新索引的额外时间取决于您在集合中有多少记录、您有多少索引以及这些索引的复杂程度。

但是,在您的情况下,您仅使用 _id 进行查询,因此您无法对索引进行更多操作。

2- 您是否使用了两次连续更新?我的意思是,一个用于$set,一个用于$push? 如果这是真的,那么你应该明确地只使用一个:

self.collection.update({'_id':uid},
                       {"$push":{'imp_date':<datevalue>,
                                 'imp_creative':<creative_id>,
                                 'imp_pid':<pid>},
                       "$set":{'geo_id':<geo id>}},
                       safe=True,upsert=True)

3- 更新操作是一个原子操作,可能会锁定其他查询。如果您要更新的文档尚未在 RAM 中,但它在磁盘中,则 mongo 必须先从磁盘中获取它,然后再更新它。如果您先执行查找操作(不会阻塞,因为它是只读操作),文档肯定会在 RAM 中,因此更新操作(锁定操作)会更快:

self.collection.findOne({'_id':uid})
self.collection.update({'_id':uid},
                       {"$push":{'imp_date':<datevalue>,
                                 'imp_creative':<creative_id>,
                                 'imp_pid':<pid>},
                       "$set":{'geo_id':<geo id>}},
                       safe=True,upsert=True)

4-如果您的文档没有像您所说的那样增长太多,则无需担心填充因子和重新分配问题。此外,在一些最近的版本中(不记得是从 2.2 还是 2.4 开始的)集合是在默认启用 powerOfTwo 选项的情况下创建的。

【讨论】:

  • 非常感谢。我根据建议 2 更改了插入语法并获得了性能提升。我尝试了建议 3,但在尝试多个线程时遇到了一些并发问题,最终导致整体性能变慢。目前我认为我能做的最好的事情是在 AWS 和分片上使用更好的机器(随着数据库在我的机器上增长并爬取大约 80M 记录,性能严重下降)。感谢所有帮助。
猜你喜欢
  • 2012-02-09
  • 2016-09-12
  • 2015-10-23
  • 2020-07-04
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多