Azure cosmosdb 在Azure Cosmos DB中,这是一个错误的分区密钥方案吗?

Azure cosmosdb 在Azure Cosmos DB中,这是一个错误的分区密钥方案吗?,azure-cosmosdb,partitioning,azure-cosmosdb-sqlapi,Azure Cosmosdb,Partitioning,Azure Cosmosdb Sqlapi,我正在创建一个Azure Cosmos数据库,以在多租户系统中存储多个客户的电话记录。用户需要按电话号码、姓名、分机号码和日期范围搜索这些电话记录。每个电话记录的结构都非常坚固(我认为),如下所示: { "id": "M7o_ddRB7VRpjUA", "ownerTime": "2458671015_202008", "ownerId": "2458671015

我正在创建一个Azure Cosmos数据库,以在多租户系统中存储多个客户的电话记录。用户需要按电话号码、姓名、分机号码和日期范围搜索这些电话记录。每个电话记录的结构都非常坚固(我认为),如下所示:

{
    "id": "M7o_ddRB7VRpjUA",
    "ownerTime": "2458671015_202008",
    "ownerId": "2458671015",
    "callTime": "2020-08-30T18:47:44.424+00:00",
    "direction": "Outbound",
    "action": "VoIP Call",
    "result": "Call connected",
    "duration": 57,
    "hasR": true,
    "hasV": false,
    "xNums": [
        "2605"
    ],
    "xIds": [
        "2204328014"
    ],
    "names": [
        "sally wayfield"
    ],
    "phoneNums": [
        "2098368307",
        "2097449211"
    ],
    "emails": [
        "sally.wayfield@company.com"
    ],
    "xNums_s": "2605",
    "xIds_s": "2204328014",
    "phoneNums_s": "2098368307 2097449211",
    "names_s": "sally wayfield",
    "emails_s": "sally.wayfield@company.com",
    "_rid": "QB1nAK5kxPMBAAAAAAAAAA==",
    "_self": "dbs/QB1nAA==/colls/QB1nAK5kxPM=/docs/QB1nAK5kxPMBAAAAAAAAAA==/",
    "_etag": "\"d2013319-0000-0500-0000-5f4c63dd0000\"",
    "_attachments": "attachments/",
    "_ts": 1598841821
}
但我一直在努力想出一个好的分区键策略。我最初的想法是保持简单,并将每个租户的帐户id指定为分区键。在上面的文档中,帐户id是
所有者id
。我对从旧数据库导入的数据做了一些基准测试,效果很好。然而,呼叫记录的数量因租户而异。我遇到的一个特别的问题是,有几个租户每天摄入大约10000条通话记录。在6个月的时间里,这相当于4GB左右。随着我们继续为这些帐户每天接收10000个呼叫记录,我们将在3年内达到每个分区20GB的限制。因此,这一战略不会奏效

我的下一个想法是将时态数据作为分区键的一部分。这似乎是有道理的,因为我们每天都在批量导入大量的时间戳数据。而且,针对该数据库的所有查询中99%将包含日期范围。我提出了一个派生的抽象值,在上面的文档中标记为
ownerTime
。此值将帐户id与时间因素(每次电话的年份和月份)组合在一起。使用此方案,每个租户每年将获得12个分区,而不是整个帐户的单个分区。每个租户的容量仍然不同,因此我们仍然会有一些大分区和一些小分区。但这种差异不会像我们每个租户有一个分区时那样极端

使用“每个租户一个分区”策略,典型的查询如下所示:

{
    "id": "M7o_ddRB7VRpjUA",
    "ownerTime": "2458671015_202008",
    "ownerId": "2458671015",
    "callTime": "2020-08-30T18:47:44.424+00:00",
    "direction": "Outbound",
    "action": "VoIP Call",
    "result": "Call connected",
    "duration": 57,
    "hasR": true,
    "hasV": false,
    "xNums": [
        "2605"
    ],
    "xIds": [
        "2204328014"
    ],
    "names": [
        "sally wayfield"
    ],
    "phoneNums": [
        "2098368307",
        "2097449211"
    ],
    "emails": [
        "sally.wayfield@company.com"
    ],
    "xNums_s": "2605",
    "xIds_s": "2204328014",
    "phoneNums_s": "2098368307 2097449211",
    "names_s": "sally wayfield",
    "emails_s": "sally.wayfield@company.com",
    "_rid": "QB1nAK5kxPMBAAAAAAAAAA==",
    "_self": "dbs/QB1nAA==/colls/QB1nAK5kxPM=/docs/QB1nAK5kxPMBAAAAAAAAAA==/",
    "_etag": "\"d2013319-0000-0500-0000-5f4c63dd0000\"",
    "_attachments": "attachments/",
    "_ts": 1598841821
}
partitionKey=/ownerId

select c.id,c.callTime,c.direction,c.action,c.result,c.duration,c.hasR,c.hasV,c.callers
from c
where
ownerId='2458671015'
and c.callTime>='2020-01-01T00:00:00 +000'
and c.callTime<='2020-08-31T23:59:59 +000'
and (CONTAINS(c.phoneNums_s, 'rus')
or CONTAINS(c.names_s, 'rus')
or CONTAINS(c.xNums_s, 'rus'))
order by c.callTime desc
正如您在
ownerTime
策略中所看到的,我正在明确计算需要搜索哪些分区(基于搜索日期范围)。我在查询中定义这些分区

在我最初的基准测试中,我试图通过这些查询检索25条记录,这些查询是针对我的一个高流量帐户(有110万条电话记录)。“每个租户一个分区”查询使用了大约2200个RU来返回一条记录。我不得不继续使用continuation令牌来获得更多的结果,每个请求使用大约2000个RU,直到我最终得到25条记录。经过多次迭代,我记不清RUs的数量。
ownerTime
分区查询使用了大约2500个RU来检索25条记录,而不必使用延续令牌


似乎
ownerTime
策略是一个更好的选择,只要所有查询都包含一个日期范围。但是我想得到一些关于这个策略的反馈。这并不完美,但似乎效果不错。我来自SQL背景,这是我第一次实现文档数据库。我这样做是为了利用改进的文本搜索和可伸缩性。将来使用
ownerTime
分区策略是否会遇到“gotcha”?根据我提供的信息,有没有更好的分区策略?

有界跨分区查询肯定比无界查询好得多,因此根据您在这里的问题中所包含的内容,我同意包含时间元素来创建合成分区键是一种很好的分区策略

这里没有解释的是,是否有其他大量运行的查询在筛选器谓词中不包含时间(或ownerId)?如果是这样,那么您将需要使用changefeed将数据第一个容器中的数据复制并保持同步到第二个容器,并使用对这些查询也有意义的分区键


另一个选择也是,特别是如果您希望对这些数据进行分析,则启用分析存储并使用Synapse Link,然后在数据上编写Spark(很快将是SQL Serverless)查询。

谢谢标记。大约99%的查询将同时使用ownerId和日期时间。另外1%将用于我们自己的后端数据分析,可以批量完成。我们希望优先考虑客户驱动的查询,这将始终包括ownerId和日期时间。我对您提到的更改提要和分析存储很感兴趣。你能提供一些关于这些工作原理的参考资料吗?现在,我们正在将分析数据存储在一个单独的数据库中,但我们也在寻求升级。当然,这里有一个关于Synapse链接的链接。以下是有关更改提要的链接: