使用MongoDB缓慢插入

时间:2014-07-03 23:40:48

标签: mongodb pymongo

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

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

(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 /秒或更快)?

我无法找到明确的建议: - 使用多个线程插入数据 -Sharding -Padding数组(我的数组增长非常慢,每个文档数组在文件末尾的平均长度为~4) - 关闭日记

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

1 个答案:

答案 0 :(得分:0)

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选项创建了集合。