2.2. 批量写操作

MongoDB 通过 db.collection.bulkWrite() (opens new window)方法来支持批量写操作(包括批量插入、更新、删除)。此外,db.collection.insertMany() (opens new window)方法支持批量插入操作。

有序和无序的操作

批量写操作可以有序或无序。

  • 对于有序列表,MongoDB 串行执行操作。如果在写操作的处理过程中发生错误,MongoDB 将不处理列表中剩余的写操作。
  • 对于无序列表,MongoDB 可以并行执行操作,但是不能保证此行为。如果在写操作的处理过程中发生错误,MongoDB 将继续处理列表中剩余的写操作。

在分片集合上执行操作的有序列表通常比执行无序列表要慢,因为对于有序列表,每个操作必须等待上一个操作完成。默认情况下,bulkWrite() (opens new window)执行有序操作。要指定无序写操作,请在选项文档中设置 ordered : false

bulkWrite() 方法

bulkWrite() (opens new window)支持以下写操作:

【示例】批量写操作示例

try {
  db.characters.bulkWrite([
    {
      insertOne: {
        document: {
          _id: 4,
          char: 'Dithras',
          class: 'barbarian',
          lvl: 4,
        },
      },
    },
    {
      insertOne: {
        document: {
          _id: 5,
          char: 'Taeln',
          class: 'fighter',
          lvl: 3,
        },
      },
    },
    {
      updateOne: {
        filter: { char: 'Eldon' },
        update: { $set: { status: 'Critical Injury' } },
      },
    },
    { deleteOne: { filter: { char: 'Brisbane' } } },
    {
      replaceOne: {
        filter: { char: 'Meldane' },
        replacement: { char: 'Tanys', class: 'oracle', lvl: 4 },
      },
    },
  ])
} catch (e) {
  print(e)
}

批量写操作策略

大量的插入操作(包括初始数据插入或常规数据导入)可能会影响分片集群的性能。对于批量插入,请考虑以下策略:

预拆分 collection

如果分片集合为空,则该集合只有一个初始 chunk (opens new window),该 chunk (opens new window)位于单个分片上。然后,MongoDB 必须花一些时间来接收数据,创建拆分并将拆分的块分发到可用的分片。为了避免这种性能成本,您可以按照拆分群集中的拆分块中的说明预拆分 collection。

无序写操作

要提高对分片集群的写入性能,请使用 bulkWrite() (opens new window),并将可选参数顺序设置为 false。mongos (opens new window)可以尝试同时将写入操作发送到多个分片。对于空集合,首先按照分片群集中的分割 chunk (opens new window)中的说明预拆分 collection。

避免单调节流

如果在一次插入操作中,分片 key 单调递增,那么所有的插入数据都会存入 collection 的最后一个 chunk,也就是存入一个分片中。因此,集群的插入容量将永远不会超过该单个分片的插入容量。

如果插入量大于单个分片可以处理的插入量,并且无法避免单调递增的分片键,那么请考虑对应用程序进行以下修改:

  • 反转分片密钥的二进制位。这样可以保留信息,并避免将插入顺序与值序列的增加关联起来。
  • 交换第一个和最后一个 16 位字以“随机”插入。