Azure Cosmos DB でのパフォーマンスの最適化:ベストプラクティスとヒント

データベースを扱う際、最適化はアプリケーションのパフォーマンスと効率にとって極めて重要です。同様に、Azure Cosmos DBでも、最適化は効率を最大化し、コストを最小限に抑え、アプリケーションのスケーラビリティを確保するために重要です。以下は、Azure Cosmos DBでパフォーマンスを最適化するためのベストプラクティスとコーディング例です。

1. 適切なパーティションキーの選択

適切なパーティションキーの選択は、Cosmos DBなどの分散データベースにとって重要です。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. 正しい Uインデックスの使用

Azure Cosmos DBでは、デフォルトで全てのプロパティにインデックスが適用されます。これは有益な場合もありますが、ストレージとRU/sコストが増加する可能性があります。クエリのパフォーマンスを向上させ、コストを最小限に抑えるために、インデックスポリシーをカスタマイズすることを検討してください。 Cosmos DBは、範囲インデックス、空間インデックス、複合インデックスの3種類のインデックスをサポートしています。 適切なタイプを賢く使用してください。

ベストプラクティス

  • インデックスから不要なフィールドを除外してください。
  • 複数フィールドのクエリには複合インデックスを使用してください。

例: カスタムインデックスポリシー

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コストは、クエリの複雑さとサイズに依存します。

バルクエグゼキュータを利用することで、操作ごとの消費RUを減少させ、コストをさらに削減できます。この最適化は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. 整合性レベルの調整

整合性レベルは、速度関連の保証を満たすために設計された特定の操作モードを定義します。 5つの整合性レベル(Strong、Bounded Staleness、Session、Consistent Prefix、Eventual)がCosmos DBで利用可能です。 各整合性レベルは、レイテンシ、可用性、スループットに影響を与えます。

ベストプラクティス

  • ほとんどのシナリオでセッション整合性を使用して、パフォーマンスとデータの整合性をバランスさせます。
  • Strong整合性はデータの整合性を保証しますが、RU/sおよびレイテンシが増加します。

例: 整合性レベルの設定

C#

 

var cosmosClient = new CosmosClient(
    "",
    "",
    new CosmosClientOptions
    {
        // パフォーマンスをバランスさせるために整合性を「セッション」に設定
		ConsistencyLevel = ConsistencyLevel.Session      
});

整合性レベルについて詳しくはこちらをご覧ください。

5. プロビジョニングスループット (RU/s) とオートスケールを賢く利用する

スループットのプロビジョニングは、Azure Cosmos DBにおいてコスト効率と最適なパフォーマンスを達成するための重要な要素です。このサービスでは、スループットを2つの方法で設定できます:

  • 固定 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. 変更フィードを活用して効率的なリアルタイム処理を行う

変更フィードは、データベースの変更を自動的にキャプチャしてポーリングの必要性を排除し、リアルタイムでイベント駆動型の処理を可能にします。これにより、クエリのオーバーヘッドが減少し、効率が向上します。

ベストプラクティス

  • リアルタイムのデータ変更が処理される必要があるシナリオ(例:リアルタイム分析、通知、アラート)には変更フィードを使用します。

例:変更フィードからの読み取り

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を設定してストレージコストを削減します。

例:期限切れデータのためのTime-to-Live(TTL)の設定

C#

 

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

Cosmos DBでは、設定できる最大Time-to-Live(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