bigywater.tech
MongoDB · 53

bulkWrite 的 ordered 与 unordered

bulkWrite 的 ordered 和 unordered 差在哪?出错时会怎样?操作之间有依赖时能不能用 unordered?这篇用带重复键的批量插入和混合操作逐个验证,还看了批次拆分。

4 对 6
同样的批量插入遇到重复键时,ordered 与 unordered 已插入的文档数
3 条
25 万个文档的批量插入被拆成的 insert 命令数
105 / 102 ms
5 万个文档的 ordered / unordered 插入耗时

ordered

实测 · 本机执行输出
  nInserted = 4;writeErrors: [(4, 11000, 'E11000 duplicate key error collection: test.o index: _id_ du')]
  集合里的 _id: [0, 1, 2, 3](第 5 个出错,后面 5 个没插)

默认 ordered:按顺序执行,第一个错误处停止,后面的操作不会执行;writeErrors 里只有那一个错误。

unordered

实测 · 本机执行输出
  nInserted = 6;writeErrors 的 index: [1, 2, 4, 7](全部 4 个错误都返回了)
  集合里的 _id: [0, 1, 2, 3, 5, 6, 8, 9]

ordered=False:出错的操作被跳过,其余照常执行,所有错误一起在 writeErrors 里返回。

操作依赖

实测 · 本机执行输出
  ordered   [insert a, update a]:  inserted 1 matched 1 modified 1;n = 11
  ordered   [update b, insert b]:  inserted 1 matched 0 modified 0;n = 1(update 先执行,什么也没匹配到)
  unordered [update b, insert b]:  inserted 1 matched 1 modified 1;n = 11(顺序不再保证)
  unordered 的 3 个操作实际发出的命令序列: [('insert', 1), ('update', 1), ('delete', 1)](驱动把同类操作分组,插入组排在更新组之前)
  ordered   的同样 3 个操作发出的命令序列: [('update', 1), ('insert', 1), ('delete', 1)](按原顺序,每次类型变化就换一条命令)

混合操作之间有依赖(先插入再更新)就必须用 ordered;unordered 下驱动会把同类操作分组,插入排在更新之前,顺序不再保证。

批次拆分

实测 · 本机执行输出
  ordered  插入 250,000 个文档:493 ms;发出的 insert 命令 [100000, 100000, 50000]
  unordered插入 250,000 个文档:476 ms;发出的 insert 命令 [100000, 100000, 50000]

一次 bulk 超过 maxWriteBatchSize(100,000)会拆成多条命令,25 万个文档拆成 100000 + 100000 + 50000 三条。

耗时

实测 · 本机执行输出
  ordered 105 ms;unordered 102 ms(单节点上差别很小)

单节点上 ordered 和 unordered 的耗时几乎一样(105 对 102 ms)。

错误详情

实测 · 本机执行输出
  details 的键: ['nInserted', 'nMatched', 'nModified', 'nRemoved', 'nUpserted', 'upserted', 'writeConcernErrors', 'writeErrors']
  writeErrors[0] 的键: ['code', 'errmsg', 'index', 'keyPattern', 'keyValue', 'op'];code=11000,index=1,keyValue={'_id': 1}

BulkWriteError.details 里有各类计数和 writeErrors,每个错误带 code、index、keyValue、op 等字段。

分步演示

bulkWrite 的 ordered 与 unordered
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MongoDB 9.0.2(Homebrew 的 mongod、mongos)/ mongosh 2.12.0 / pymongo 4.18.3;每个实验在临时目录里起全新的 mongod(独立 dbpath,端口 9900 以上,只监听 127.0.0.1,WiredTiger 缓存 0.25 GB),需要副本集或分片集群时在本机起多个进程;命令输出来自真实的 mongosh,批量写入、计时与多线程用 pymongo;计时用 time.perf_counter,数字每次运行会有小幅抖动,ObjectId、时间戳等每次运行都不同。命令序列通过 pymongo 的 CommandListener 记录
    • 没有验证:分片集群上 unordered 的并行效果;副本集 w:majority 下两者的耗时差别;超过 48 MB 消息上限的拆分(这里只验证了文档数拆分);带事务的 bulkWrite;驱动之外的 mongosh bulkWrite 与新的 client.bulkWrite 命令
    京ICP备2026067502号-1京公网安备11010502063487号