在 Azure Cosmos DB 中优化性能:最佳实践和技巧

在使用数据库时,优化对于应用程序性能和效率至关重要。同样,在 Azure Cosmos DB 中,优化对于最大化效率、最小化成本和确保应用程序有效扩展也至关重要。以下是一些最佳实践以及编码示例,以优化 Azure Cosmos DB 的性能。

1. 选择合适的分区键

为像 Cosmos DB 这样的分布式数据库选择合适的分区键至关重要。良好的分区键确保数据在分区中均匀分布,减少热点,并提高性能。

在 Azure Cosmos DB 的设计阶段,选择分区键虽然简单,但非常重要。一旦 我们 选择了 分区键,便无法在原地更改它。

最佳实践

  • 选择具有高基数(许多唯一值)的分区键。
  • 确保它均匀分布读取和写入。
  • 将相关数据放在一起,以最小化跨分区查询。

示例:创建具有最佳分区键的容器

C#

 

var database = await cosmosClient.CreateDatabaseIfNotExistsAsync("YourDatabase");
var containerProperties = new ContainerProperties
{
    Id = "myContainer",
    PartitionKeyPath = "/customerId"  // Partition key selected to ensure balanced distribution
}; 

// 创建具有 400 RU/s 预配吞吐量的容器
var container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

2. 正确地使用索引

在Azure Cosmos DB中,默认情况下对所有属性应用索引,这可能是有益的,但可能会导致增加存储和RU/s成本。为了提高查询性能并最小化开支,请考虑自定义索引策略。 Cosmos DB支持三种类型的索引:范围索引、空间索引和复合索引。 明智地使用适当的类型。

最佳实践

  • 排除不必要的字段进行索引。
  • 对于多字段查询,请使用复合索引。

示例:自定义索引策略

C#

 

{
    "indexingPolicy": {
        "automatic": true,
        "indexingMode": "consistent",  // Can use 'none' or 'lazy' to reduce write costs
        "includedPaths": [
            {
                "path": "/orderDate/?",  // Only index specific fields like orderDate
                "indexes": [
                    {
                        "kind": "Range",
                        "dataType": "Number"
                    }
                ]
            }
        ],
        "excludedPaths": [
            {
                "path": "/largeDataField/*"  // Exclude large fields not used in queries
            }
        ]
    }
}

示例:添加复合索引以优化查询

C#

 

{
    "indexingPolicy": {
        "compositeIndexes": [
            [
                { "path": "/lastName", "order": "ascending" },
                { "path": "/firstName", "order": "ascending" }
            ]
        ]
    }
}

您可以在此处阅读更多关于索引类型的信息

3. 优化查询

在Azure Cosmos DB中,高效的查询对于最小化请求单位(RU/s)和提高性能至关重要。RU/s成本取决于查询的复杂性和大小。

利用批量执行器可以进一步降低成本,减少每次操作消耗的RUs。这种优化有助于有效管理RU使用量,降低您的整体Cosmos DB开支。

最佳实践

  • 使用SELECT查询时应限制查询量,仅检索必要的属性。
  • 通过在查询中提供分区键,避免跨分区查询。
  • 在索引字段上使用过滤器以降低查询成本。

示例:获取客户记录

C#

 

var query = new QueryDefinition("SELECT c.firstName, c.lastName FROM Customers c WHERE c.customerId = @customerId")
    .WithParameter("@customerId", "12345");

var iterator = container.GetItemQueryIterator<Customer>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")  // Provide partition key to avoid cross-partition query
});

while (iterator.HasMoreResults)
{
    var response = await iterator.ReadNextAsync();
    foreach (var customer in response)
    {
        Console.WriteLine($"{customer.firstName} {customer.lastName}");
    }
}

4. 一致性级别调整

一致性级别定义了旨在满足与速度相关的保证的特定操作模式。 在Cosmos DB中提供了五种一致性级别(Strong、Bounded Staleness、Session、Consistent Prefix和Eventual)。每个一致性级别都会影响延迟、可用性和吞吐量。

最佳实践

  • 大多数情况下使用会话一致性以平衡性能和数据一致性。
  • 强一致性保证数据一致性但会增加 RU/s 和延迟。

示例:设置一致性级别

C#

 

var cosmosClient = new CosmosClient(
    "",
    "",
    new CosmosClientOptions
    {
        // 将一致性设置为“会话”以获得平衡的性能
		ConsistencyLevel = ConsistencyLevel.Session      
});

了解更多关于一致性级别的信息在此处

5. 明智地使用预配吞吐量(RU/s)和自动缩放

在 Azure Cosmos DB 中,预配吞吐量是实现成本效益和最佳性能的关键因素。该服务允许您以两种方式配置吞吐量:

  • 固定 RU/s预先定义的每秒请求单位(RU/s)的恒定级别,适用于具有一致性性能需求的工作负载。
  • 自动缩放一种动态选项,根据工作负载的波动自动调整吞吐量,提供可伸缩性,同时避免在低活动期间过度预配。

选择适当的吞吐量模型有助于有效地平衡性能需求和成本管理。

最佳实践

  • 对于可预测的工作负载,手动预配吞吐量。
  • 对于不可预测或突发的工作负载,使用自动缩放。

示例:使用自动缩放预配吞吐量

C#

 

var throughputProperties = ThroughputProperties.CreateAutoscaleThroughput(maxThroughput: 4000);  // Autoscale up to 4000 RU/s 
var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
	Id = "autoscaleContainer",
	PartitionKeyPath = "/userId"
}, throughputProperties);

示例:为稳定工作负载手动设置固定 RU/s 

C#

 

var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
    Id = "manualThroughputContainer",
    PartitionKeyPath = "/departmentId"
}, throughput: 1000);  // Fixed 1000 RU/s

6. 利用变更 Feed 实现高效的实时处理

变更订阅通过自动捕获数据库中的变更,允许实时事件驱动处理,消除了轮询的需要。这减少了查询开销并提高了效率。

最佳实践

  • 在需要处理实时数据更改的场景中使用变更订阅(例如,实时分析、通知、警报)。

示例:读取变更订阅

C#

 

var iterator = container.GetChangeFeedIterator(
ChangeFeedStartFrom.Beginning(),
ChangeFeedMode.Incremental);
while (iterator.HasMoreResults)
{
    var changes = await iterator.ReadNextAsync();
    foreach (var change in changes)
    {
        Console.WriteLine($"Detected change: {change.Id}");
        // 处理变更(例如,触发事件,更新缓存)
    }
}

7. 利用生存时间(TTL)实现自动数据过期

如果您有一些数据仅在有限时间内相关,例如日志或会话数据,启用 Azure Cosmos DB 中的生存时间(TTL)可以帮助管理存储成本。TTL 在指定的保留期后会自动删除过期数据,消除了手动数据清理的需要。这种方法不仅减少了存储的数据量,还通过删除过时或不必要的信息确保数据库的成本效益得到优化。

最佳实践

  • 为需要自动过期的数据容器设置 TTL,以减少存储成本。

示例:为过期数据设置生存时间(TTL)

C#

 

{
    "id": "sessionDataContainer",
    "partitionKey": { "paths": ["/sessionId"] },
    "defaultTtl": 3600  // 1 hour (3600 seconds)
}

在 Cosmos DB 中,可以设置的最大生存时间(TTL)值为 365 天(1 年)。 这意味着数据在创建或最后修改后的 1 年内到期后可以被自动删除,具体取决于您如何配置 TTL。

8. 避免跨分区查询

跨分区查询会显著增加 RU/s 和延迟。为了避免这种情况:

最佳实践

  • 在查询中始终包含分区键。
  • 设计您的分区策略以最小化跨分区访问。

示例:使用分区键查询以避免跨分区查询

C#

 

var query = new QueryDefinition("SELECT * FROM Orders o WHERE o.customerId = @customerId")
    .WithParameter("@customerId", "12345"); 

var resultSetIterator = container.GetItemQueryIterator<Order>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")
});

while (resultSetIterator.HasMoreResults)
{
    var response = await resultSetIterator.ReadNextAsync();
    foreach (var order in response)
    {
        Console.WriteLine($"Order ID: {order.Id}");
    }
}

结论

这些提示在开发过程中非常有效。通过实施有效的分区策略、自定义索引策略、优化查询、调整一致性级别以及选择适当的吞吐量配置模型,您可以大大提高 Azure Cosmos DB 部署的性能和效率。这些优化不仅增强了可扩展性,还有助于管理成本,同时提供高性能的数据库体验。

Source:
https://dzone.com/articles/optimizing-performance-in-azure-cosmos-db