You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB含50万文档集合pymongo写入速度慢的优化咨询

系统信息
  • 操作系统:Ubuntu 20.04 LTS
  • 硬件配置:80GB内存、1TB SSD、i7-12700k

当前集合中文档平均大小16KB,累计已有50万条文档,随着集合规模扩大,写入耗时呈线性增长趋势。目前写入15万条文档需耗时10小时,与以下代码计算的预测结果一致:

def f(num):
    return 0.0004*num+0.9594

sum=0
for i in range(500,650):
    sum+=f(i*1000)

>>> sum/3600
>>> 9.61497

潜在优化方向设想

  • 使用C++ Mongo引擎进行写入
  • 为Mongod分配更多内存

监控日志

  • iotop显示mongod仅使用不到1%的IO容量,写入速度约为10-20KB/s
  • htop显示mongod仅占用约16GB内存
  • 磁盘尚有约300GB SSD空间可用

核心写入逻辑(伪代码)

docs=[...]
for doc in docs:
   doc["last_updated"]=str(datetime.now())
   
   doc_from_db = collection.find_one({"key":doc["key"]})
   
   new_dict = minify(doc)
   if doc_from_db is None:
      collection.insert_one(new_dict)
   else:
      collection.replace_one({"key":doc["key"]},new_dict,upsert=true)

针对性优化方案

  1. 消除冗余查询,利用原生upsert特性
    现有逻辑先执行find_one再判断插入/替换,完全可以直接通过replace_one的upsert=True参数完成原子操作,省去一次数据库读查询。修改后逻辑:

    docs=[...]
    for doc in docs:
        doc["last_updated"]=str(datetime.now())
        new_dict = minify(doc)
        collection.replace_one({"key":doc["key"]}, new_dict, upsert=True)
    
  2. 批量操作替代单条循环
    单条循环会产生大量网络往返和数据库事务开销,改用bulk_write批量执行更新/插入:

    from pymongo import UpdateOne
    
    docs=[...]
    operations = []
    for doc in docs:
        doc["last_updated"]=str(datetime.now())
        new_dict = minify(doc)
        operations.append(
            UpdateOne(
                {"key": doc["key"]},
                {"$replaceRoot": {"newRoot": new_dict}},
                upsert=True
            )
        )
        # 每1000条执行一次批量提交
        if len(operations) == 1000:
            collection.bulk_write(operations)
            operations = []
    # 处理剩余未提交的操作
    if operations:
        collection.bulk_write(operations)
    
  3. 添加关键索引
    检查key字段是否存在索引,若无则立即创建单字段索引:

    db.collection.createIndex({"key": 1})
    

    无索引时,find_one和replace_one会触发全表扫描,这是写入耗时随数据量线性增长的核心原因之一。添加索引后查询效率会呈数量级提升,索引维护的开销远小于全表扫描的耗时。

  4. 调整MongoDB内存缓存配置
    当前mongod仅占用16GB内存,可将WiredTiger缓存大小调整为物理内存的50%-60%(比如40GB),让更多数据和索引驻留内存,减少磁盘IO。修改mongod.conf:

    storage:
      wiredTiger:
        engineConfig:
          cacheSizeGB: 40
    

    重启mongod生效。

  5. 优化时间字段存储
    避免将datetime转换为字符串存储,直接存入MongoDB原生日期类型,既节省空间又消除转换开销:

    from datetime import datetime
    doc["last_updated"] = datetime.now()
    
  6. 关于C++引擎的优先级
    改用C++客户端确实能提升性能,但优先级低于上述优化项。Python的pymongo性能足够支撑需求,优先解决逻辑、索引和配置层面的瓶颈后,再考虑更换客户端。

内容的提问来源于stack exchange,提问作者user20289089

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 08:30:51