我对Mongo复合分片键有疑问。我们假设我的文档结构如下:
{
"players": [
{
"id": "12345",
"name": "John",
},
{
"id": "23415",
"name": "Doe",
}
]
}
玩家嵌入的文件总是存在且总是2.我认为" players.0.id"和#34; players.1.id"作为分片键应该是一个很好的选择,因为它不是单调的并且是均匀分布的。
我从文档中可以理解的是:
换句话说,如果我查询Collection以获取John播放的所有游戏(作为玩家1或玩家2),查询将被发送到一个块或所有块?
答案 0 :(得分:1)
您无法创建分片键,其中键的一部分是多键索引(即数组字段上的索引)。这在Shard Key Index Type中提到:
分片键索引不能是指定分片键字段上的多键索引,文本索引或地理空间索引的索引。
如果players
字段下只有两个项目,为什么不创建两个子文档而不是使用数组?对于文档中有多个不确定数字项的用例,数组通常很有用。例如,此结构可能适用于您的用例:
{
"players": {
"player_1": {
"id" : 12345,
"name": "John"
},
"player_2": {
"id": 54321,
"name": "Doe"
}
}
}
然后,您可以创建一个索引,如:
> db.test.createIndex({'players.player_1.id':1, 'players.player_2.id':1})
要回答您的问题,如果您正在使用此分片键,则:
无法保证相同的player_1.id
和player_2.id
位于相同的块上。这取决于您的数据分布。
如果您将John查询为player_1 OR player_2
,则查询将发送到所有分片。这是因为您有一个复合索引作为分片键,并且您正在非前缀字段中搜索完全匹配。
详细说明问题2:
您正在执行的查询是:
db.test.find({$or: [
{'players.player_1.id':123},
{'players.player_2.id':123}
]})
在复合索引中,索引首先按player_1.id
排序,然后对于每个player_1.id
,存在排序player_2.id
。例如,如果您有10个文档包含player_1.id
和player_2.id
的某些值组合,则可以像这样显示索引:
player_1.id | player_2.id
------------|-------------
0 | 10
0 | 123
1 | 100
1 | 123
2 | 123
2 | 150
123 | 10
123 | 100
123 | 123
123 | 150
请注意,值player_2.id: 123
在表格中多次出现,每个player_1.id
出现一次。另请注意,对于每个player_1.id
值,player_2.id
值都会在其中进行排序。
这就是MongoDB的复合索引的工作原理以及它的排序方式。复合索引的细微差别太长,无法在此解释,但详细信息在Compound Indexes page
中有解释。这种排序方法的效果是,在索引中分布了许多相同的player_2.id
值。由于整体索引仅按player_1.id
排序,因此如果不指定player_2.id
,则无法找到确切的player_1.id
。因此,上述查询将被发送到所有分片。