必须用insert_many()批量插入,不能循环调用insert_one();需显式await、控制单批≤1000条、预生成唯一_id并建索引、配置maxpoolsize和超时。

Motor批量插入必须用insert_many(),不能用insert_one()循环
Motor不支持同步阻塞式批量操作,所有写入都必须显式声明为异步。直接对列表逐个调用insert_one()不仅慢,还会因协程未await而报RuntimeWarning: coroutine 'Collection.insert_one' was never awaited。真正有效的批量入口只有insert_many(),它原生返回一个awaitable对象。
实操建议:
- 传入的文档列表不能含
ObjectId字段(除非你自己生成并确保唯一),否则可能触发重复ID冲突 - 默认不校验文档结构,若需跳过非法文档而非中断整个批次,加参数
ordered=False - 单次
insert_many()建议控制在1000条以内,太大容易超MongoDB默认的16MB BSON限制
必须await结果,且要处理BulkWriteError
insert_many()返回的是一个InsertManyResult对象,但你得先await它完成,否则拿不到实际插入状态。常见错误是忘记await,或只检查result.acknowledged却忽略具体失败项。
实操建议:
- 总是用
try/except捕获motor.core.AgnosticBulkWriteError(注意不是pymongo.errors.BulkWriteError) - 失败时通过
error.details['writeErrors']定位哪几条出错、错误码是什么(如11000代表唯一键冲突) - 如果启用了
ordered=False,inserted_ids仍会包含成功插入的ID,但顺序可能和输入列表不一致
插入前手动补_id可避免并发重复与性能抖动
MongoDB默认在服务端生成_id,但在高并发异步场景下,多个协程同时请求ID可能导致短暂锁争用,实测QPS下降约15%。更严重的是,若没设唯一索引,两次相同数据可能被分别插入——因为服务端生成的_id不同,但业务逻辑上它们是重复的。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
实操建议:
- 用
ObjectId()或uuid4().hex在Python层预生成_id,确保业务主键语义明确 - 若依赖时间序,可用
ObjectId.from_datetime()构造带时间戳的ID,方便后续按时间范围查询 - 补
_id后务必在对应字段建唯一索引,否则无法拦截重复提交
别忽略连接池与超时配置,否则批量插入会静默卡住
Motor底层复用pymongo连接池,但默认配置对异步批量不友好:最大连接数maxPoolSize=100看似够用,一旦有慢查询占满连接,新insert_many()就会排队等待,表现为协程长时间无响应,且不抛异常。
实操建议:
- 初始化
MotorClient时显式设maxPoolSize=200(根据服务器内存和并发量调整) - 为每次
insert_many()加session和timeout:例如await collection.insert_many(docs, session=session, timeout=5) - 生产环境务必启用
serverSelectionTimeoutMS=3000,防止DNS解析失败导致无限等待
批量插入的边界情况比看起来多:ID生成策略、错误恢复粒度、连接资源竞争,这些地方不动手试一次根本意识不到问题在哪。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










