PyMongo 插入具有约 100M 记录的极其缓慢的数据库
PyMongo Insert excruciating slow data base with ~ 100M records
我在 MongoDB(大约 200 sec/insert)中遇到极慢的插入,我完全不确定为什么。
我有一个包含匿名用户名 (int)、匿名评论 ID (int) 和评论的 CSV 文件。所有这些都以字符串形式读入,但前两个字段可以毫无问题地转换为整数。
数据库包含 100M 条记录的集合,现在正在尝试构建一个映射用户及其评论 ID,并将其写入另一个集合。
大约有 6 万用户分布着 1 亿条评论。即为每个用户构建 user_id = [comment_id0,...,comment_idN] 并将其插入数据库以更快地获取所有用户评论。
def save_user_comments(dataset):
usrs = defaultdict(list)
updatebar = tqdm(total = 100000000, desc = 'Generating user-comment map', leave = False)
pool = mp.Pool()
for i, (user_id, comment_id, _) in enumerate(dataset):
usrs[str(user_id)].append(comment_id)
updatebar.update(1)
prev = 0
keys, vals = list(usrs.keys()), list(usrs.values())
results = pool.map_async(write_user, zip(keys, vals)).get()
progbar = tqdm(total = 67377, desc = 'Users Inserted', leave = False )
def write_user(itempair):
usr, comments = itempair
db = MongoClient(host = some_ip, port = some_port).GenderSpectrum
table = db.user
if db.user.find_one({'user_id': str(usr)}):
progbar.update(1)
return
u_obj = {}
obj = db.data.find_one({'user_id': str(usr)})
u_obj['comment_ids'] = comments
u_obj['_id'] = str(usr)
u_obj['is_female'] = obj['is_female']
u_obj['user_id'] = str(usr)
db.user.insert_one(u_obj)
progbar.update(1)
return 1
我在这段代码中看到的唯一会减慢速度的地方是为每个插入创建一个新连接。但是,尝试使用一个连接(同时使用单个和多个文档插入)插入一批 500 个文档时,速度会更慢。 运行 这段代码也是顺序排列的。
有人有更好的建议吗?
MongoDB版本:v3.4.9
PyMongo 版本:3.5.1
Python版本:3.5.3
OS: Ubuntu 17.4
插入本身可能非常快,循环的其他部分似乎很慢。如果 "user_id" 没有被索引,那么这可能是最慢的部分:
db.data.find_one({'user_id': str(usr)})
在 "data" 集合中的 user_id 上创建索引。只做一次:
db.data.create_index([('user_id', 1)])
这可能需要几分钟,之后 "find_one" 会快得多。
您还为每个插入创建一个新的 MongoClient,这也会稍微降低您的代码速度。在程序运行期间创建 MongoClient 一次:将其声明为全局变量,而不是 "write_user" 函数中的局部变量。
我在 MongoDB(大约 200 sec/insert)中遇到极慢的插入,我完全不确定为什么。
我有一个包含匿名用户名 (int)、匿名评论 ID (int) 和评论的 CSV 文件。所有这些都以字符串形式读入,但前两个字段可以毫无问题地转换为整数。
数据库包含 100M 条记录的集合,现在正在尝试构建一个映射用户及其评论 ID,并将其写入另一个集合。 大约有 6 万用户分布着 1 亿条评论。即为每个用户构建 user_id = [comment_id0,...,comment_idN] 并将其插入数据库以更快地获取所有用户评论。
def save_user_comments(dataset):
usrs = defaultdict(list)
updatebar = tqdm(total = 100000000, desc = 'Generating user-comment map', leave = False)
pool = mp.Pool()
for i, (user_id, comment_id, _) in enumerate(dataset):
usrs[str(user_id)].append(comment_id)
updatebar.update(1)
prev = 0
keys, vals = list(usrs.keys()), list(usrs.values())
results = pool.map_async(write_user, zip(keys, vals)).get()
progbar = tqdm(total = 67377, desc = 'Users Inserted', leave = False )
def write_user(itempair):
usr, comments = itempair
db = MongoClient(host = some_ip, port = some_port).GenderSpectrum
table = db.user
if db.user.find_one({'user_id': str(usr)}):
progbar.update(1)
return
u_obj = {}
obj = db.data.find_one({'user_id': str(usr)})
u_obj['comment_ids'] = comments
u_obj['_id'] = str(usr)
u_obj['is_female'] = obj['is_female']
u_obj['user_id'] = str(usr)
db.user.insert_one(u_obj)
progbar.update(1)
return 1
我在这段代码中看到的唯一会减慢速度的地方是为每个插入创建一个新连接。但是,尝试使用一个连接(同时使用单个和多个文档插入)插入一批 500 个文档时,速度会更慢。 运行 这段代码也是顺序排列的。
有人有更好的建议吗?
MongoDB版本:v3.4.9
PyMongo 版本:3.5.1
Python版本:3.5.3
OS: Ubuntu 17.4
插入本身可能非常快,循环的其他部分似乎很慢。如果 "user_id" 没有被索引,那么这可能是最慢的部分:
db.data.find_one({'user_id': str(usr)})
在 "data" 集合中的 user_id 上创建索引。只做一次:
db.data.create_index([('user_id', 1)])
这可能需要几分钟,之后 "find_one" 会快得多。
您还为每个插入创建一个新的 MongoClient,这也会稍微降低您的代码速度。在程序运行期间创建 MongoClient 一次:将其声明为全局变量,而不是 "write_user" 函数中的局部变量。