MongoDB复合分片键

时间:2018-02-03 14:28:24

标签: mongodb sharding

我对Mongo复合分片键有疑问。我们假设我的文档结构如下:

{
   "players": [
      {
        "id": "12345",
        "name": "John",
      },
      {
        "id": "23415",
        "name": "Doe",
      }
   ]
}

玩家嵌入的文件总是存在且总是2.我认为" players.0.id"和#34; players.1.id"作为分片键应该是一个很好的选择,因为它不是单调的并且是均匀分布的。

我从文档中可以理解的是:

  1. 所有相同的文件" players.0.id"或者相同" players.1.id"应该被保存到同一个Chunk中,或者
  2. 所有相同的文件" players.0.id"和#34; players.1.id"应该被保存到同一个Chunk中。
  3. 换句话说,如果我查询Collection以获取John播放的所有游戏(作为玩家1或玩家2),查询将被发送到一个块或所有块?

1 个答案:

答案 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})

要回答您的问题,如果您正在使用此分片键,则:

  1. 无法保证相同的player_1.idplayer_2.id位于相同的块上。这取决于您的数据分布。

  2. 如果您将John查询为player_1 OR player_2,则查询将发送到所有分片。这是因为您有一个复合索引作为分片键,并且您正在非前缀字段中搜索完全匹配。

  3. 详细说明问题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.idplayer_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。因此,上述查询将被发送到所有分片。