如何定义 CosmosDB 复合索引来优化 GROUP BY 子句、聚合系统函数(MIN、MAX)和过滤谓词?

问题描述 投票:0回答:1

我有一个包含以下几行文档架构的集合

{
    "CategoryParentId": "{guid}",
    "CategoryId": "{guid}",
    "ProductType": "{string}",
    "Size": {int},
    "Price": {decimal},
    "Discount": {decimal}
}

我执行查询来检索给定产品类型和尺寸的每个类别的最低价格和最大折扣:

SELECT p.CategoryParentId, p.CategoryId, MIN(p.Price) minPrice, MAX(p.Discount)
FROM p
WHERE p.ProductType = 'Foo' AND p.Size = 5
GROUP BY p.CategoryParentId, p.CategoryId 

借助以下复合索引,此查询的成本约为 500 RU:

        [
            {
                "path": "/CategoryParentId",
                "order": "ascending"
            },
            {
                "path": "/CategoryId",
                "order": "ascending"
            },
            {
                "path": "/Price",
                "order": "ascending"
            },
            {
                "path": "/Discount",
                "order": "descending"
            }
        ]

我想添加一个更具体的复合索引,其中包括 ProductType 和 Size 属性,当包含为过滤谓词时,这将为我的查询产生更少的 RU 成本。

我尝试添加以下附加复合索引,这是原始索引的变体,还包括 ProductType 和 Size:

        [
            {
                "path": "/ProductType",
                "order": "ascending"
            },
            {
                "path": "/Size",
                "order": "ascending"
            },
            {
                "path": "/CategoryParentId",
                "order": "ascending"
            },
            {
                "path": "/CategoryId",
                "order": "ascending"
            },
            {
                "path": "/Price",
                "order": "ascending"
            },
            {
                "path": "/Discount",
                "order": "descending"
            }
        ]

创建索引后,查询成本仍然保持在 500 RU 左右。

但是,如果我将查询修改为也按 ProductType 和 Size 分组,例如:

SELECT p.ProductType, p.Size, p.CategoryParentId, p.CategoryId, MIN(p.Price) minPrice, MAX(p.Discount)
FROM p
WHERE p.ProductType = 'Foo' AND p.Size = 5
GROUP BY p.ProductType, p.Size, p.CategoryParentId, p.CategoryId

成本降低至仅 70 RU,明显更好。

但是,分组的附加字段意味着查询返回的记录比我需要的多,我必须减少客户端的结果集才能找到每个类别的实际最佳价格和最大折扣。这并不理想,但它表明,如果我在分组依据中包含两个字段,则可以利用新索引来提高性能,但是仅将它们包含在谓词中,因为在原始查询中不使用索引。

有没有一种方法可以表达复合索引,以使用原始查询和过滤谓词实现 70 RU 性能,以避免冗余的 group by 字段?

azure azure-cosmosdb azure-cosmosdb-sqlapi
1个回答
0
投票

让我们尝试分步骤解决这个问题。

第 1 步:普通索引排除所有属性,仅包含 ProductTypeSize,因为这些是您要过滤的属性。

第 2 步:如果您有针对 2 个或更多属性的过滤器,也可以使用复合索引。所以尝试制作以下综合索引。

[
    {
        "path": "/CategoryParentId",
        "order": "ascending"
    },
    {
        "path": "/CategoryId",
        "order": "ascending"
    }
]

第 3 步:如果您查看 [文档][1],它指出:

如果查询筛选一个或多个属性并且具有不同的属性 ORDER BY 子句中的属性,添加以下内容可能会有所帮助 过滤器中的属性添加到 ORDER BY 子句。

因此,如果您使用我建议的复合索引,则需要使用 order by 子句修改查询,如下所示。

SELECT p.CategoryParentId, p.CategoryId, MIN(p.Price) minPrice, MAX(p.Discount)
FROM p
WHERE p.ProductType = 'Foo' AND p.Size = 5
ORDER BY p.ProductType ASC,  p.Size ASC
GROUP BY p.CategoryParentId, p.CategoryId 

目前没有索引可以帮助进行 MIN 和 MAX 聚合。因此,从您的综合指数中删除价格和折扣。

第4步:您可以尝试添加普通索引以包含CategoryParentId和CategoryId,看看是否可以提高性能。

分区可能有助于提高性能。例如,如果您的数据库按 ProductType 进行分区,它也可能有助于提高性能。 [1]:https://learn.microsoft.com/en-us/azure/cosmos-db/index-policy#queries-with-a-filter-and-order-by

© www.soinside.com 2019 - 2024. All rights reserved.