MongoDB插入CSV数据耗时长,如何使用多线程优化写入速度
优化CSV导入MongoDB的多线程实现方案
你当前65万行9.5秒的插入性能已经属于正常范围,若要进一步缩短耗时,可以采用「批次分片+多线程并发插入」的方案,既避免全量读取占用过高内存,也能充分利用数据库IO等待的空窗期提升导入效率。
现有代码的问题
- 第一版全量
insert_many方案:一次性读取整个CSV到内存,遇到GB级大文件时会直接占满内存导致程序崩溃 - 第二版流式单条插入方案:逐行调用
insert_one,单条操作的网络IO开销被放大了65万倍,实际插入速度会比你第一版慢至少10倍以上,完全不推荐使用
多线程优化实现
核心逻辑:用标准库concurrent.futures.ThreadPoolExecutor实现多线程,先将CSV按固定批次拆分,每个线程负责插入一个批次的数据,全程流式读取不需要加载全量文件到内存。
import csv import pymongo import time from concurrent.futures import ThreadPoolExecutor # 可根据自身机器配置调整最优参数 BATCH_SIZE = 10000 # 每批插入的行数 MAX_WORKERS = 4 # 并发线程数,建议设为CPU核心数的1~2倍 def batch_insert(collection, batch): """单批次插入函数,供线程调用""" collection.insert_many(batch) def import_csv_to_mongo(csv_path, db_name, collection_name): # 初始化Mongo连接,pymongo默认自带连接池,可安全用于多线程 client = pymongo.MongoClient('localhost', 27017) collection = client[db_name][collection_name] executor = ThreadPoolExecutor(max_workers=MAX_WORKERS) # 流式读取CSV,按批次拆分 batch = [] futures = [] with open(csv_path, 'r', encoding='utf-8') as f: reader = csv.DictReader(f) for row in reader: batch.append(row) # 攒够一个批次就提交给线程池执行 if len(batch) >= BATCH_SIZE: # 拷贝当前批次,避免后续修改batch影响已提交的任务 futures.append(executor.submit(batch_insert, collection, batch.copy())) batch.clear() # 插入最后不足一批的剩余数据 if batch: futures.append(executor.submit(batch_insert, collection, batch)) # 等待所有插入任务执行完成 for future in futures: future.result() executor.shutdown() client.close() print(f"所有数据插入完成") if __name__ == "__main__": start = time.time() # 替换为你自己的文件路径、库名、集合名 import_csv_to_mongo("path/to/your/file.csv", "donorschoose", "MapData") print(f"总耗时:{time.time() - start} 秒")
额外性能优化建议
- 导入前先删除目标集合的非必要索引,全部插入完成后再重建索引:插入过程中更新索引会占大量额外开销,删除单条索引可以让插入速度提升30%以上
- 若对数据一致性要求不高,可以在初始化MongoClient时设置
w=0的写策略,不需要等待数据库写入确认,速度可以进一步提升 - 可以用
pandas.read_csv替代标准库的csv模块读取文件,pandas的CSV读取是C语言实现,大文件读取速度比纯Python实现快2~5倍
内容的提问来源于stack exchange,提问作者Kevin Truong
相关产品推荐
相关产品推荐

