在MongoDB中,数据根据一个称为分片键(Shared Key) 的字段进行分片。根据指定字段按照指定分片方式(哈希分片、范围分片)将数据拆分到mongo集群里的不同服务器中
分片键的选择非常关键,它应该能够确保数据均匀分布,避免热点问题。
分片键通常是在文档中的一个字段,MongoDB根据这个字段的值来决定将文档存储在哪个分片上
通过增加更多的分片来处理更多的负责。通过增加更多的分片来处理更多的负载。分片键的选择和分片集群的规划是关键的设计决策,因为它们直接影响了系统的性能和可扩展性
当我们在使用条件查询时,如果查询条件中包含了分片键,MongoDB就可以利用分片键来进行数据定位,确定数据存储在哪个分片上,从而只在特定的分片上进行查询, 而不是在整个集群中搜搜,可以大大减少查询的范围,提高查询效率
最好在MongoDB指令(如查找、更新、删除)操作时,条件都包含分片键,这样可以提高查询效率。但在实际业务中,常常不同的db操作指令,可能会有自己的索引,而索引不一定都能命中分片键。 这种情况下就不能实现所有的条件都包含分片键了。
举个例子:
现在有一个umsg库,索引、分片键声明如下
"umsg": {
"indexes" : [
{
"index": [
["_id", 1] //索引1
],
"options": {
}
},
{
"index": [
["avatarID", 1] //索引2
],
"options": {
}
}
],
"shard_key": {"_id": "hashed"} // _id 分片键,分片方式:哈希分片
},
1)update指令更新数据,指令操作失败
更新指令:
db.getCollection('umsg').update({id:1}, {$set:{a:1}})
更新报错:
A single update on a sharded collection must contain an exact match on _id (and have the collection default collation) or contain the shard key (and have the simple collation). Update request: { q: { id: 1.0 }, u: { $set: { a: 1.0 } }, multi: false, upsert: false }, shard key pattern: { _id: "hashed" }
2)deleteOne指令删除数据,指令操作失败
删除指令:
db.getCollection('umsg').deleteOne({id:1})
删除结果:
Failed to execute script.
Error:
WriteError({
"index" : 0,
"code" : 61,
"errmsg" : "A single delete on a sharded collection must contain an exact match on _id (and have the collection default collation) or contain the shard key (and have the simple collation). Delete request: { q: { id: 1.0 }, limit: 1 }, shard key pattern: { _id: \"hashed\" }",
"op" : {
"q" : {
"id" : 1
},
"limit" : 1
}
}) :
WriteError({
"index" : 0,
"code" : 61,
"errmsg" : "A single delete on a sharded collection must contain an exact match on _id (and have the collection default collation) or contain the shard key (and have the simple collation). Delete request: { q: { id: 1.0 }, limit: 1 }, shard key pattern: { _id: \"hashed\" }",
"op" : {
"q" : {
"id" : 1
},
"limit" : 1
}
})
WriteError@src/mongo/shell/bulk_api.js:458:48
mergeBatchResults@src/mongo/shell/bulk_api.js:855:49
executeBatch@src/mongo/shell/bulk_api.js:919:13
Bulk/this.execute@src/mongo/shell/bulk_api.js:1163:21
DBCollection.prototype.deleteOne@src/mongo/shell/crud_api.js:375:17
@(shell):1:1
3) findAndModify、findOneAndUpdate、findOneAndDelete 指令 ,指令操作失败
查找并更新指令
db.getCollection('umsg').findAndModify({id:1}, {$set:{a:1}})
查找单条数据并更新指令
db.getCollection('umsg').findOneAndUpdate({id:1}, {$set:{a:1}})
茶轴单条数据并删除指令
db.getCollection('umsg').findOneAndDelete({id:1}, {$set:{a:1}})
操作结果:
Failed to execute script.
Error:
Uncaught exception: Error: findAndModifyFailed failed: {
"ok" : 0,
"errmsg" : "Query for sharded findAndModify must contain the shard key",
"code" : 61,
"codeName" : "ShardKeyNotFound",
"operationTime" : Timestamp(1710298791, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1710298791, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
DBCollection.prototype.findAndModify@src/mongo/shell/collection.js:725:15
@(shell):1:1
4)findOne和find查询指令,正常
db.getCollection('umsg').find({id:1})
db.getCollection('umsg').findOne({id:1})
结论:
查找条件不一定要包含分片键(会去不同的分片上查询,效率低),修改到文档数据的指令操作条件都要包含分片键。