如何加速 Cosmos DB 聚合查询?

How to speed up a Cosmos DB aggregate query?

我们的 cosmos db 聚合查询似乎很慢并且花费了很多 RU。以下是详细信息(另请参见下面的屏幕截图):2.4s 和 3222RUs 用于计算 414k 记录的结果集。这也只是一个计数。通常我们希望一次对多个字段进行求和(可能只在一个分区内),但这样做的性能要差得多。

此集合中有 200 万条记录。我们正在使用 Cosmos DB w/SQL API。这个特定的集合按 country_code 划分,在法国 ("FR") 有 414,732 条记录,其余在美国。文档大小平均为 917 字节,可能最小为 800 字节,最大为 1300 字节。

请注意,我们还尝试了更稀疏的分区键,例如 device_id(其中有 200 万个,此处每个设备 1 个文档),但此查询的结果更差。 c.calcuated.flag1 字段仅表示我们要计数的 "state"(实际上我想总结 8 个状态)。

这个集合的索引是默认的,它使用"consistent"索引模式,索引所有字段(包括数字和字符串的范围索引)。 RU 设置为 20,000,DB 上没有其他 activity。

让我知道您对此的看法。是否可以合理地使用 Cosmos DB 在不增加我们的 RU 费用和花费很长时间的情况下对字段进行一些求和或计数?虽然 2.4s 并不可怕,但我们确实需要亚秒级查询来处理这种事情。我们的应用程序(基于物联网)通常需要单独的文档,但有时也需要对一个国家/地区的所有文档进行此类计数。

有没有提高性能的方法?

对于显示的特定查询,不需要指定table名称,您可以尝试限制1,一些性能会有所提高。例如:

SELECT COUNT(1) FROM c WHERE country_code="FR" AND calculated.flag=1 LIMIT 1

此外,不要忘记仔细分析 你的查询执行,我在 Cosmos 中不确定,但像 PostreSQL 方法,EXPLAIN ANALYSE。还要确保您使用的是 最佳类型的变量 ,例如,varchar(2) 而不是 varchar(3)。如果您要过滤它们(正如您指出的那样),我建议 更改每个国家/地区的字符类型 。例如FR=1,GR=2等等。这也将提高性能。最后,如果国家代码和计算出的标志相关,则创建一个定义它们的唯一变量。如果这些都不起作用,请检查客户端性能,甚至硬件。

两个想法:

尝试运行以下,看看你是否得到不同的 运行 次:

SELECT COUNT(1) FROM c WHERE country_code="FR"

重要! calculated.flag1 字段,如果它不是持久的,可能会给出问题 - 对于每个 document/record - 数据库引擎必须计算结果,因此高 RU。 你能优化计算字段吗? (分解它们,还是将计算作为查询的一部分?)

第二个建议是尝试让您定义一个复合索引

{  
        "automatic":true,
        "indexingMode":"Consistent",
        "includedPaths":[  
            {  
                "path":"/*"
            }
        ],
        "excludedPaths":[  

        ],
        "compositeIndexes":[  
            [  
                {  
                    "path":"/country_code",
                    "order":"ascending"
                },
                {  
                    "path":"/calculated",
                    "order":"descending"
                }
            ]
        ]
    }

另见Composite indexing policy examples

Manage indexing policies in Azure Cosmos DB 看看你在哪里编辑它

Cosmos DB 团队现在对聚合性能和索引的使用方式进行了一些重大更改。这是他们的索引 "v2" 策略,最近才推出(它可能不适用于所有帐户,如果您有需要升级的旧数据库,请联系 MSFT)。

您可以将新结果与我最初发布的图片进行比较。

您现在会注意到文档加载时间显示为 0 毫秒,检索到的文档大小为 0 字节。我可以确认的加载时间现在确实非常快,因此从服务器端测量时可能低于 1 毫秒。文档大小为 0 更有意义,因为不需要为此检索文档(仅根据索引计数)。

最后你可以看到 RUs 从 3222 下降到 7.4 !!!!相当大的差异。

在单个分区内一次对多个列求和现在也非常高效,我们可以一次对 200 万份文档进行大约 8 次求和,具有约 50 个 RU,从函数测量时大约需要 20-70 毫秒 API 端点(因此包括网络时间)。

Cosmos DB 团队仍需要做更多的工作以允许跨分区 multi-column 聚合,但我们现在的改进非常有前途。