次の方法で共有


実際の例を使用してデータをモデル化およびパーティション分割する方法

この記事は、実際のデータ設計演習に取り組む方法を示すために、 データ モデリングパーティション分割プロビジョニングスループット など、いくつかの Azure Cosmos DB の概念に基づいています。

通常、リレーショナル データベースを使用する場合は、データ モデルを設計するための習慣が身に付いている可能性があります。 具体的な制約だけでなく、Azure Cosmos DB の固有の強みもあるため、これらのベスト プラクティスのほとんどはうまく変換されないため、最適でないソリューションに発展する可能性があります。 この記事の目的は、項目のモデリングからエンティティコロケーションとコンテナーのパーティション分割まで、Azure Cosmos DB で実際のユース ケースをモデル化する完全なプロセスをガイドすることです。

この記事の概念を示す例については、 このコミュニティで生成されたソース コードをダウンロードまたは表示します。

Important

コミュニティの共同作成者がこのコード例を投稿しました。 Azure Cosmos DB チームは、そのメンテナンスをサポートしていません。

シナリオ

この演習では、 ユーザー が投稿を作成できるブログ プラットフォームのドメインを検討 します。 ユーザーは、それらの投稿を 好き にしたり、 コメント を追加したりすることもできます。

ヒント

一部の単語は 斜体 で強調表示され、モデルが操作する "モノ" の種類を識別します。

仕様にさらに要件を追加する:

  • フロント ページには、最近作成された投稿のフィードが表示されます。
  • ユーザーのすべての投稿、投稿のすべてのコメント、投稿のすべてのいいねを取得できます。
  • 投稿は、作成者のユーザー名と、コメントやいいねの数と共に返されます。
  • コメントやいいね! は、作成したユーザーのユーザー名と共に返されます。
  • リストとして表示される場合、投稿はコンテンツの要約を切り捨てて表示するだけで済みます。

主なアクセス パターンを特定する

まず、ソリューションのアクセス パターンを識別することで、初期仕様に何らかの構造を与えます。 Azure Cosmos DB のデータ モデルを設計する場合は、モデルがそれらの要求を効率的に処理できるように、モデルがどの要求に対応する必要があるかどうかを理解することが重要です。

全体的なプロセスのフォローを容易にするために、これらの異なる要求をコマンドまたはクエリとして分類し、 コマンド クエリ責任分離 (CQRS) からいくつかのボキャブラリを借用します。 CQRS では、コマンドは書き込み要求 (つまり、システムを更新する意図) であり、クエリは読み取り専用の要求です。

プラットフォームが公開する要求の一覧を次に示します。

  • [C1] ユーザーを作成または編集する
  • [Q1] ユーザーを取得する
  • [C2] 投稿を作成または編集する
  • [Q2] 投稿を取得する
  • [Q3] ユーザーの投稿を短い形式で一覧表示する
  • [C3] コメントを作成する
  • [Q4] 投稿のコメントを一覧表示する
  • [C4] 投稿を「いいね!」する
  • [Q5] 投稿のいいね!を一覧表示する
  • [Q6] 短い形式で作成された x 個の最新の投稿を一覧表示する (フィード)

この段階では、各エンティティ (ユーザー、投稿など) に含まれる内容の詳細については考えていません。 この手順は、通常、リレーショナル ストアに対して設計するときに最初に取り組む手順の 1 つです。 最初に、テーブル、列、外部キーなどの観点からこれらのエンティティがどのように変換されるかを把握する必要があるため、この手順から始めます。 書き込み時にスキーマを強制しないドキュメント データベースに関する懸念ははるかに少なくなります。

この要求の一覧がテスト スイートになるため、最初からアクセス パターンを特定することが重要です。 データ モデルを反復処理するたびに、各要求を調べて、そのパフォーマンスとスケーラビリティを確認します。 各モデルで使用される要求ユニット (RU) を計算し、それらを最適化します。 これらのモデルはすべて既定のインデックス作成ポリシーを使用し、特定のプロパティにインデックスを付けることでオーバーライドできます。これにより、RU の消費量と待機時間がさらに向上します。

V1: 最初のバージョン

まず、 userspostsの 2 つのコンテナーから始めます。

Users コンテナー

このコンテナーには、ユーザー項目のみが格納されます。

{
    "id": "<user-id>",
    "username": "<username>"
}

このコンテナーは idでパーティション分割します。つまり、そのコンテナー内の各論理パーティションに含まれる項目は 1 つだけです。

投稿コンテナ

このコンテナーは、投稿、コメント、いいねなどのエンティティをホストします。

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "title": "<post-title>",
    "content": "<post-content>",
    "creationDate": "<post-creation-date>"
}

{
    "id": "<comment-id>",
    "type": "comment",
    "postId": "<post-id>",
    "userId": "<comment-author-id>",
    "content": "<comment-content>",
    "creationDate": "<comment-creation-date>"
}

{
    "id": "<like-id>",
    "type": "like",
    "postId": "<post-id>",
    "userId": "<liker-id>",
    "creationDate": "<like-creation-date>"
}

このコンテナーは、 postIdでパーティション分割します。つまり、そのコンテナー内の各論理パーティションには、1 つの投稿、その投稿のすべてのコメント、およびその投稿のすべてのいいね! が含まれます。

このコンテナーでホストされる 3 種類のエンティティを区別するために、このコンテナーに格納されている項目に type プロパティを導入しました。

また、次の理由から、関連するデータを埋め込む代わりに参照することを選択しました。

  • ユーザーが作成できる投稿の数に上限はありません。
  • 投稿は任意に長くすることができます。
  • 投稿に含めることができるコメントやいいね!の数に上限はありません。
  • 投稿自体を更新することなく、投稿にコメントやいいね!を追加できるようにしたいと考えています。

これらの概念の詳細については、 Azure Cosmos DB でのデータ モデリングに関するページを参照してください。

モデルのパフォーマンスはどの程度の成果を上げていますか?

次に、最初のバージョンのパフォーマンスとスケーラビリティを評価します。 以前に識別された各要求について、待機時間と消費する要求ユニットの数を測定します。 この測定は、ユーザー 1 人あたり 5 ~ 50 件の投稿を持つ 100,000 人のユーザーと、投稿あたり最大 25 個のコメントと 100 件のいいね!を含むダミー データ セットに対して行われます。

[C1]ユーザーを作成または編集する

この要求は、 users コンテナー内の項目を作成または更新するだけで簡単に実装できます。 要求は、 id パーティション キーのおかげで、すべてのパーティションにうまく分散されます。

ユーザー コンテナーに 1 つの項目を書き込む図。

Latency 要求ユニット パフォーマンス
7 ミリ秒 5.71 Ru

[Q1]ユーザーを取得する

ユーザーの取得は、 users コンテナーから対応する項目を読み取ることによって行われます。

ユーザー コンテナーから 1 つの項目を取得する図。

Latency 要求ユニット パフォーマンス
2 ミリ秒 1 Ru

[C2]投稿を作成または編集する

[C1] と同様に、posts コンテナーに書き込むだけです。

投稿コンテナーに 1 つの投稿項目を書き込む図。

Latency 要求ユニット パフォーマンス
9 ミリ秒 8.76 Ru

[Q2]投稿を取得する

まず、 posts コンテナーから対応するドキュメントを取得します。 しかし、これは十分ではありません。仕様に従って、投稿の作成者のユーザー名、コメントの数、投稿のいいねの数を集計する必要もあります。 一覧表示されている集計では、さらに 3 つの SQL クエリを発行する必要があります。

投稿の取得と追加データの集計の図。

各クエリは、それぞれのコンテナーのパーティション キーをフィルター処理します。これは、パフォーマンスとスケーラビリティを最大限に高めたいものです。 しかし、最終的には 1 つの投稿を返すために 4 つの操作を実行する必要があるため、次のイテレーションで改善します。

Latency 要求ユニット パフォーマンス
9 ms 19.54 Ru

[Q3]ユーザーの投稿を短い形式で一覧表示する

まず、その特定のユーザーに対応する投稿をフェッチする SQL クエリを使用して、目的の投稿を取得する必要があります。 ただし、作成者のユーザー名とコメントやいいねの数を集計するために、さらに多くのクエリを発行する必要があります。

ユーザーのすべての投稿を取得し、追加データを集計する図。

この実装には、多くの欠点があります。

  • コメントやいいね!の数を集計するクエリは、最初のクエリによって返される投稿ごとに発行する必要があります。
  • メイン クエリでは、 posts コンテナーのパーティション キーがフィルター処理されないため、コンテナー全体でファンアウトとパーティション スキャンが行われます。
Latency 要求ユニット パフォーマンス
130 ミリ秒 619.41 Ru

[C3]コメントを作成する

コメントは、 posts コンテナーに対応する項目を書き込むことで作成されます。

投稿コンテナーに 1 つのコメント 項目を書き込む図。

Latency 要求ユニット パフォーマンス
7 ミリ秒 8.57 Ru

[Q4]投稿のコメントを一覧表示する

まず、その投稿のすべてのコメントをフェッチするクエリから始めます。また、コメントごとに個別にユーザー名を集計する必要もあります。

投稿のすべてのコメントを取得し、追加データを集計する図。

メイン クエリではコンテナーのパーティション キーをフィルター処理しますが、ユーザー名を個別に集計すると、全体的なパフォーマンスが低下します。 後で改善します。

Latency 要求ユニット パフォーマンス
23 ミリ秒 27.72 Ru

[C4]投稿を「いいね!」する

[C3] と同様に、posts コンテナーに対応する項目を作成します。

投稿コンテナーに 1 つの (いいね) 項目を書き込む図。

Latency 要求ユニット パフォーマンス
6 ミリ秒 7.05 Ru

[Q5]投稿のいいね!を一覧表示する

[Q4] と同様に、その投稿のいいねを照会し、ユーザー名を集計します。

投稿のすべてのいいねを取得し、追加データを集計する図。

Latency 要求ユニット パフォーマンス
59 ミリ秒 58.92 Ru

[Q6]短い形式で作成された x 個の最新の投稿を一覧表示する (フィード)

作成日の降順で並べ替えられた posts コンテナーに対してクエリを実行し、各投稿のコメントといいねのユーザー名と数を集計して、最新の投稿をフェッチします。

最新の投稿を取得し、追加データを集計する図。

ここでも、最初のクエリでは、 posts コンテナーのパーティション キーをフィルター処理しないため、コストのかかるファンアウトがトリガーされます。これは、より大きな結果セットを対象とし、 ORDER BY 句で結果を並べ替えるのでさらに悪くなります。これにより、要求ユニットの観点から見るとコストが高くなります。

Latency 要求ユニット パフォーマンス
306 ミリ秒 2063.54 Ru

V1 のパフォーマンスについて考える

前のセクションで直面したパフォーマンスの問題を見ると、次の 2 つの主要な問題クラスを特定できます。

  • 一部の要求では、返す必要があるすべてのデータを収集するために複数のクエリを発行する必要があります。
  • 一部のクエリでは、対象となるコンテナーのパーティション キーがフィルター処理されないため、スケーラビリティを妨げるファンアウトが生じる可能性があります。

最初の問題から始めて、これらの各問題を解決しましょう。

V2: 非正規化を導入して読み取りクエリを最適化する

場合によっては、より多くの要求を発行する必要がある理由は、最初の要求の結果に返す必要があるすべてのデータが含まれていないためです。 データを非正規化すると、Azure Cosmos DB のような非リレーショナル データ ストアを操作するときに、データセット全体でこの種の問題が解決されます。

この例では、投稿アイテムを変更して、投稿の作成者のユーザー名、コメントの数、いいねの数を追加します。

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "userUsername": "<post-author-username>",
    "title": "<post-title>",
    "content": "<post-content>",
    "commentCount": <count-of-comments>,
    "likeCount": <count-of-likes>,
    "creationDate": "<post-creation-date>"
}

また、コメントや同様の項目を変更して、それらを作成したユーザーのユーザー名を追加します。

{
    "id": "<comment-id>",
    "type": "comment",
    "postId": "<post-id>",
    "userId": "<comment-author-id>",
    "userUsername": "<comment-author-username>",
    "content": "<comment-content>",
    "creationDate": "<comment-creation-date>"
}

{
    "id": "<like-id>",
    "type": "like",
    "postId": "<post-id>",
    "userId": "<liker-id>",
    "userUsername": "<liker-username>",
    "creationDate": "<like-creation-date>"
}

コメントと like カウントを非正規化する

私たちが達成したいのは、コメントなどを追加するたびに、対応する投稿の commentCount または likeCount もインクリメントすることです。 postId posts コンテナーをパーティション分割すると、新しい項目 (コメントなど) とそれに対応する投稿が同じ論理パーティションに配置されます。 その結果、 ストアド プロシージャ を使用してその操作を実行できます。

コメント ([C3]) を作成すると、 posts コンテナーに新しい項目を追加するのではなく、そのコンテナーで次のストアド プロシージャを呼び出します。

function createComment(postId, comment) {
  var collection = getContext().getCollection();

  collection.readDocument(
    `${collection.getAltLink()}/docs/${postId}`,
    function (err, post) {
      if (err) throw err;

      post.commentCount++;
      collection.replaceDocument(
        post._self,
        post,
        function (err) {
          if (err) throw err;

          comment.postId = postId;
          collection.createDocument(
            collection.getSelfLink(),
            comment
          );
        }
      );
    })
}

このストアド プロシージャは、投稿の ID と新しいコメントの本文をパラメーターとして受け取り、次の操作を行います。

  • 投稿を取得します。
  • は、 commentCountをインクリメントします。
  • 投稿を置き換えます。
  • 新しいコメントを追加します。

ストアド プロシージャはアトミック トランザクションとして実行されるため、 commentCount の値とコメントの実際の数は常に同期されます。

新しいいいねを追加して likeCountをインクリメントするときは、明らかに同様のストアド プロシージャを呼び出します。

ユーザー名の非正規化

ユーザーが異なるパーティションに配置されるだけでなく、別のコンテナーに配置されるため、ユーザー名には異なるアプローチが必要です。 パーティションとコンテナー間でデータを非正規化する必要がある場合は、ソース コンテナーの 変更フィードを使用できます。

この例では、ユーザーがユーザー名を更新するたびに対応するために、 users コンテナーの変更フィードを使用します。 その場合は、 posts コンテナーで別のストアド プロシージャを呼び出して変更を反映します。

投稿コンテナーへのユーザー名の非正規化の図。

function updateUsernames(userId, username) {
  var collection = getContext().getCollection();
  
  collection.queryDocuments(
    collection.getSelfLink(),
    `SELECT * FROM p WHERE p.userId = '${userId}'`,
    function (err, results) {
      if (err) throw err;

      for (var i in results) {
        var doc = results[i];
        doc.userUsername = username;

        collection.upsertDocument(
          collection.getSelfLink(),
          doc);
      }
    });
}

このストアド プロシージャは、ユーザーの ID とユーザーの新しいユーザー名をパラメーターとして受け取り、次の操作を行います。

  • は、 userId に一致するすべての項目 (投稿、コメント、いいね! など) を取得します。
  • これらの各項目に対して次の手順を実行します。
    • userUsernameを置き換えます。
    • この項目を置き換えます。

Important

この操作は、 posts コンテナーのすべてのパーティションでこのストアド プロシージャを実行する必要があるため、コストがかかります。 ほとんどのユーザーがサインアップ時に適切なユーザー名を選択し、変更することはないと想定しているため、この更新プログラムはほとんど実行されません。

V2 のパフォーマンスの向上は何ですか?

V2 のパフォーマンス向上について説明します。

[Q2]投稿を取得する

これで、非正規化が行われたので、その要求を処理するために必要なのは 1 つの項目をフェッチすることだけです。

非正規化された投稿コンテナーから 1 つの項目を取得する図。

Latency 要求ユニット パフォーマンス
2 ミリ秒 1 Ru

[Q4]投稿のコメントを一覧表示する

ここでも、ユーザー名をフェッチした追加の要求を省略し、最終的にパーティション キーをフィルター処理する 1 つのクエリを実行できます。

非正規化された投稿のすべてのコメントを取得する図。

Latency 要求ユニット パフォーマンス
4 ミリ秒 7.72 Ru

[Q5]投稿のいいね!を一覧表示する

いいねを一覧表示する場合とまったく同じ状況。

非正規化された投稿のすべてのいいねを取得する図。

Latency 要求ユニット パフォーマンス
4 ミリ秒 8.92 Ru

V3: すべての要求がスケーラブルであることを確認する

全体的なパフォーマンスの向上を見ると、まだ 2 つの要求が完全に最適化されていません。 これらの要求は [Q3][Q6] です。 これらは、対象となるコンテナーのパーティション キーでフィルター処理されないクエリを含む要求です。

[Q3]ユーザーの投稿を短い形式で一覧表示する

このリクエストは、V2 で導入された改善により、クエリの数を削減しています。

ユーザーの非正規化された投稿を短い形式で一覧表示するクエリを示す図。

ただし、残りのクエリは、 posts コンテナーのパーティション キーに対してフィルター処理を行っていません。

この状況を考える方法は簡単です。

  • 特定のユーザーのすべての投稿を取得するために、このリクエストはuserIdでフィルターする必要があります。
  • posts コンテナーに対して実行され、パーティション分割userIdがないため、うまく動作しません。
  • 当然、 userIdでパーティション分割されたコンテナーに対してこの要求を実行することで、パフォーマンスの問題を解決します。
  • このようなコンテナー ( users コンテナー) が既に存在することが判明しました。

そのため、 users コンテナーに投稿全体を複製することで、非正規化の第 2 レベルを導入します。 それを行うことで、パーティション分割されているディメンションが異なるだけの、投稿のコピーを実質的に取得し、その userId によっていっそう効率的に取得できるようになります。

users コンテナーには、次の 2 種類の項目が含まれるようになりました。

{
    "id": "<user-id>",
    "type": "user",
    "userId": "<user-id>",
    "username": "<username>"
}

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "userUsername": "<post-author-username>",
    "title": "<post-title>",
    "content": "<post-content>",
    "commentCount": <count-of-comments>,
    "likeCount": <count-of-likes>,
    "creationDate": "<post-creation-date>"
}

この例では:

  • ユーザーと投稿を区別するために、ユーザーアイテムに type フィールドを導入しました。
  • また、ユーザー項目に userId フィールドも追加しました。これは id フィールドと重複しますが、 users コンテナーが userId でパーティション分割されているため (以前のように id されていない) 必要です。

この非正規化を実現するために、もう一度変更フィードを使用します。 今回は、 posts コンテナーの変更フィードに対応して、新しい投稿または更新された投稿を users コンテナーにディスパッチします。 また、投稿を一覧表示しても完全なコンテンツを返す必要がないため、プロセスで切り捨てることができます。

ユーザーのコンテナーへの投稿の非正規化の図。

これで、コンテナーのパーティション キーをフィルター処理して、クエリを users コンテナーにルーティングできるようになりました。

非正規化されたユーザーのすべての投稿を取得する図。

Latency 要求ユニット パフォーマンス
4 ミリ秒 6.46 Ru

[Q6]短い形式で作成された x 個の最新の投稿を一覧表示する (フィード)

ここでも同様の状況に対処する必要があります。V2 で導入された非正規化によって不要なクエリが増えた後でも、残りのクエリはコンテナーのパーティション キーでフィルター処理されません。

短い形式で作成された x 個の最新の投稿を一覧表示するクエリを示す図。

同じアプローチに従って、この要求のパフォーマンスとスケーラビリティを最大化するには、1 つのパーティションにのみヒットする必要があります。 限られた数の項目だけを返す必要があるので、1 つのパーティションにのみヒットすると考えられます。 ブログ プラットフォームのホーム ページを設定するには、データ セット全体を改ページすることなく、最新の 100 件の投稿を取得するだけで済みます。

そのため、この最後の要求を最適化するために、この要求の処理専用の 3 つ目のコンテナーを設計に導入します。 私たちの投稿をその新しい feed コンテナーにして非正規化する。

{
    "id": "<post-id>",
    "type": "post",
    "postId": "<post-id>",
    "userId": "<post-author-id>",
    "userUsername": "<post-author-username>",
    "title": "<post-title>",
    "content": "<post-content>",
    "commentCount": <count-of-comments>,
    "likeCount": <count-of-likes>,
    "creationDate": "<post-creation-date>"
}

type フィールドはこのコンテナーをパーティション分割します。これは常に項目内で post になります。 これにより、このコンテナー内のすべての項目が同じパーティションに配置されます。

非正規化を実現するには、以前に導入した変更フィード パイプラインをフックして、その新しいコンテナーに投稿をディスパッチするだけです。 注意すべき重要な点の 1 つは、最新の 100 件の投稿のみを保存する必要があることです。そうしないと、コンテナーの内容がパーティションの最大サイズを超える可能性があります。 この制限は、ドキュメントがコンテナーに追加されるたびに ポストトリガー を呼び出すことによって実装できます。

フィード コンテナーへの投稿の非正規化の図。

コレクションを切り詰める事後トリガーの本体を次に示します。

function truncateFeed() {
  const maxDocs = 100;
  var context = getContext();
  var collection = context.getCollection();

  collection.queryDocuments(
    collection.getSelfLink(),
    "SELECT VALUE COUNT(1) FROM f",
    function (err, results) {
      if (err) throw err;

      processCountResults(results);
    });

  function processCountResults(results) {
    // + 1 because the query didn't count the newly inserted doc
    if ((results[0] + 1) > maxDocs) {
      var docsToRemove = results[0] + 1 - maxDocs;
      collection.queryDocuments(
        collection.getSelfLink(),
        `SELECT TOP ${docsToRemove} * FROM f ORDER BY f.creationDate`,
        function (err, results) {
          if (err) throw err;

          processDocsToRemove(results, 0);
        });
    }
  }

  function processDocsToRemove(results, index) {
    var doc = results[index];
    if (doc) {
      collection.deleteDocument(
        doc._self,
        function (err) {
          if (err) throw err;

          processDocsToRemove(results, index + 1);
        });
    }
  }
}

最後の手順では、クエリを新しい feed コンテナーに再ルーティングします。

最新の投稿を取得する図。

Latency 要求ユニット パフォーマンス
9 ミリ秒 16.97 Ru

Conclusion

さまざまなバージョンの設計で導入された全体的なパフォーマンスとスケーラビリティの向上を見てみましょう。

V1 V2 V3
[C1] 7 ms / 5.71 RU 7 ms / 5.71 RU 7 ms / 5.71 RU
[Q1] 2 ms / 1 RU 2 ms / 1 RU 2 ms / 1 RU
[C2] 9 ms / 8.76 RU 9 ms / 8.76 RU 9 ms / 8.76 RU
[Q2] 9 ms / 19.54 RU 2 ms / 1 RU 2 ms / 1 RU
[Q3] 130 ms / 619.41 RU 28 ms / 201.54 RU 4 ms / 6.46 RU
[C3] 7 ms / 8.57 RU 7 ms / 15.27 RU 7 ms / 15.27 RU
[Q4] 23 ms / 27.72 RU 4 ms / 7.72 RU 4 ms / 7.72 RU
[C4] 6 ms / 7.05 RU 7 ms / 14.67 RU 7 ms / 14.67 RU
[Q5] 59 ms / 58.92 RU 4 ms / 8.92 RU 4 ms / 8.92 RU
[Q6] 306 ms / 2063.54 RU 83 ms / 532.33 RU 9 ms / 16.97 RU

読み取り負荷の高いシナリオを最適化しました

書き込み要求 (コマンド) を犠牲にして、読み取り要求 (クエリ) のパフォーマンス向上に向けた取り組みが集中していることに気付くかもしれません。 多くの場合、書き込み操作は変更フィードを介して後続の非正規化をトリガーするようになりました。これにより、計算コストが高くなり、具体化に時間がかかります。

これは、ほとんどのソーシャル アプリと同様に、ブログ プラットフォームが読み取り負荷が高いことによって、読み取りパフォーマンスに重点を置いていることを正当化します。 読み取り負荷の高いワークロードは、処理する必要がある読み取り要求の量が、通常、書き込み要求の数よりも桁違いに大きいことを示します。 そのため、読み取り要求のパフォーマンスを向上させるために、書き込み要求の実行コストを高くすることが理にかなっています。

これまでに行った最も極端な最適化を見ると 、[Q6] は 2000 以上の RU からわずか 17 RU に変更されました。これは、アイテムあたり約 10 RU のコストで投稿を非正規化することで実現しました。 投稿の作成や更新よりも多くのフィード要求を処理するため、全体的な節約を考慮すると、この非正規化のコストはごくわずかです。

非正規化は段階的に適用できます

この記事で説明したスケーラビリティの向上には、データ セット全体のデータの非正規化と重複が含まれます。 これらの最適化は、初日から実施する必要はありません。 パーティション キーをフィルター処理するクエリは大規模にパフォーマンスが向上しますが、ほとんど呼び出されない場合や、限られたデータ セットに対してクロスパーティション クエリを使用できる場合があります。 プロトタイプを構築するだけの場合や、小規模で制御されたユーザー ベースで製品を発売するだけの場合は、後でこれらの改善を行う余裕が生じる可能性があります。 重要なのは、 モデルのパフォーマンスを監視 して、モデルを導入するタイミングとタイミングを決定できることです。

更新プログラムを他のコンテナーに配布するために使用する変更フィードには、これらの更新がすべて永続的に格納されます。 この永続化により、システムに既に多数のデータが存在する場合でも、コンテナーの作成以降のすべての更新を要求し、非正規化されたビューを 1 回限りのキャッチアップ操作としてブートストラップすることができます。

次のステップ

この実用的なデータ モデリングとパーティション分割の概要の後、次の記事を確認して概念を確認できます。