MongoDB 复合分片键
MongoDB compound shard key
我对 Mongo 复合分片键有疑问。假设我的文档结构如下:
{
"players": [
{
"id": "12345",
"name": "John",
},
{
"id": "23415",
"name": "Doe",
}
]
}
Players embedded documents are always present and always 2. 我认为 "players.0.id" 和 "players.1.id" 作为分片键应该是一个不错的选择,因为它们不是单调的并且分布均匀。
我无法从文档中理解的是:
- 所有具有相同 "players.0.id" 或相同 "players.1.id" 的文档应该保存到同一个块中,或者
- 具有相同 "players.0.id" 和相同 "players.1.id" 的所有文档都应该保存到同一个块中。
换句话说,如果我查询集合以获取 John(作为玩家 1 或玩家 2)玩过的所有游戏,查询将发送到一个块还是所有块?
您不能创建部分键是多键索引(即数组字段上的索引)的分片键。 Shard Key Index Type:
中提到了这一点
A shard key index cannot be an index that specifies a multikey index, a text index or a geospatial index on the shard key fields.
如果 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
会在同一个块上。这将取决于您的数据分布。
如果您以 player_1 OR player_2
的身份查询 John,该查询将发送到所有分片。这是因为您有一个复合索引作为分片键,并且您正在搜索非前缀字段上的精确匹配。
详细说明问题 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
在 table 中出现多次,每个 player_1.id
出现一次。另请注意,对于每个 player_1.id
值,player_2.id
值在其中排序。
这就是 MongoDB 的复合索引的工作原理和排序方式。复合索引有更多的细微差别,在这里解释太长了,但细节在 Compound Indexes page
中解释
这种排序方法的效果是,索引中分布着许多相同的 player_2.id
值。由于整体索引仅根据 player_1.id
排序,因此如果不指定 player_1.id
则无法找到准确的 player_2.id
。因此,上述查询将发送到所有分片。
我对 Mongo 复合分片键有疑问。假设我的文档结构如下:
{
"players": [
{
"id": "12345",
"name": "John",
},
{
"id": "23415",
"name": "Doe",
}
]
}
Players embedded documents are always present and always 2. 我认为 "players.0.id" 和 "players.1.id" 作为分片键应该是一个不错的选择,因为它们不是单调的并且分布均匀。
我无法从文档中理解的是:
- 所有具有相同 "players.0.id" 或相同 "players.1.id" 的文档应该保存到同一个块中,或者
- 具有相同 "players.0.id" 和相同 "players.1.id" 的所有文档都应该保存到同一个块中。
换句话说,如果我查询集合以获取 John(作为玩家 1 或玩家 2)玩过的所有游戏,查询将发送到一个块还是所有块?
您不能创建部分键是多键索引(即数组字段上的索引)的分片键。 Shard Key Index Type:
中提到了这一点A shard key index cannot be an index that specifies a multikey index, a text index or a geospatial index on the shard key fields.
如果 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
会在同一个块上。这将取决于您的数据分布。如果您以
player_1 OR player_2
的身份查询 John,该查询将发送到所有分片。这是因为您有一个复合索引作为分片键,并且您正在搜索非前缀字段上的精确匹配。
详细说明问题 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
在 table 中出现多次,每个 player_1.id
出现一次。另请注意,对于每个 player_1.id
值,player_2.id
值在其中排序。
这就是 MongoDB 的复合索引的工作原理和排序方式。复合索引有更多的细微差别,在这里解释太长了,但细节在 Compound Indexes page
中解释这种排序方法的效果是,索引中分布着许多相同的 player_2.id
值。由于整体索引仅根据 player_1.id
排序,因此如果不指定 player_1.id
则无法找到准确的 player_2.id
。因此,上述查询将发送到所有分片。