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 位字以“随机”插入。