如何在Cosmos DB中对大量记录进行快速聚合?

时间:2019-03-15 08:44:11

标签: azure-cosmosdb azure-cosmosdb-sqlapi

我目前有一些电子邮件建模文档,类似于以下内容

{
    "AccountId": "AccountId",
    "Brand": "MyBrand",
    "Product": "MyProduct",
    "Metadata": {
        "Campaign": "EmailCampaign1",
        "Metadata2": "Some other info",
    },
    "Status": {
        "State": "delivered",
        "DeliveryEvents": [
            {
                "Event": "delivered",
                "DateTimeOccured": "2019-03-14T12:25:12Z",
            },
            {
                "Event": "processed",
                "DateTimeOccured": "2019-03-14T12:25:09Z"
            }
        ]
    },
    "id": "AnId",
    "CreatedAt": 1552566306,
    "Stats": {
        "DeliveryStats": {
            "processed": true,
            "deferred": false,
            "delivered": true,
            "dropped": false,
            "bounce": false
        }
    }
}

作为参考,AccountId当前是分区密钥。

我想在COUNT上做一个DeliveryStats,您可以在其中过滤以下一项或多项:

  • AccountId
  • Brand
  • Metadata(搜索键值对)
  • CreatedAt(例如,两个日期之间)。

这是我目前使用的示例查询,用于通过一些过滤器获取已处理项目的计数。理想情况下,我想获得所有不同DeliveryStats的数量,但现在看来这不可能。

SELECT VALUE COUNT(1) FROM c WHERE c.Stats.DeliveryStats.processed = true AND c.Brand = 'MyBrand' AND c.Metadata.Campaign = 'EmailCampaign1'

所有查询内容均已编制索引。

现在,正如您所期望的,这在较小的数据集上是非常快的,但是一旦您开始进入数百万个数据集,似乎就在加载每个文档(或者我真的读错了查询指标)

我的问题是,此查询写得正确吗?我还能做些什么来加快这种查询的速度?

打开以重组数据或存储补充数据。

1 个答案:

答案 0 :(得分:1)

原则上,假设谓词值已被索引且具有足够的选择性,该查询似乎还可以。没有看到数据,查询指标和索引定义很难准确地确定任何内容,但是..

个体索引选择性

您的索引数据是否足够个人选择性? CosmosDB索引存储单个属性的值,因此,即使三个索引的组合可能具有足够的选择性,CosmosDB最有可能必须选择一个作为要扫描的主要索引。如果索引的选择性不够好,那么即使组合的选择性足够好,也会导致性能下降。

在这种情况下,您可以考虑将pf的值单独合并,而不能将没有足够选择性的列值合并到单个哈希索引属性中以进行查找。例如:

{
    "AccountId": "AccountId",
    "Brand": "MyBrand",
    "Metadata": {
        "Campaign": "EmailCampaign1",
    },
    ...
    "MergedForLookup": "MyBrand_EmailCampaign_processed"
    ...
}

显然可以通过提供的任何可能的组合来支持N个可选过滤器,但这很棘手,但您会想到:以存储速度换取

如果找不到很好的反规范化助手,并且绝对需要按许多组合进行搜索,那么您可能必须包括用于搜索的外部索引。例如,查看如何add Azure Search

跨分区查询

下一个候选对象是您正在执行跨分区查询。基本上,每个分区上的一个查询= N个查询。如果您的数据增长到数百万,则很可能它具有许多分区(= accountIds)+您的数据将在内部划分为多个物理分区,这肯定会产生影响。如果可能,应检查是否在AccountId上包含过滤器可以缓解这种情况。 如果可能,请强制使用“帐户ID”过滤器。

count()是否有效地使用了索引

即使使用单分区查询,如果查询的速度仍然比您预期的慢,则有报告称 count()查询的效率不如预期。检查以下问题,然后投票: "Make COUNT() aware of indexes" on CosmosDB Feedback

..计数所有不同的DeliveryStats。

是的,单个查询尚不支持AFAIK,但尚可。检查请求 "Add Group By support for Aggregate Functions"

现在,如果固定值相对较少,则只需依次对每个统计信息执行这5个查询或任何查询。如果它们每个都正确地使用了分区/索引,那么它仍然应该是闪电般的(准确地说是5倍闪电:P)。