DynamoDBで1対1、1対多、および多対多の関係をモデル化する方法

F_SO_K:

DynamoDBでこれらの関係をモデル化する最良の方法は何ですか?

  • 1対1の関係
  • 1対多の関係
  • 多対多の関係
F_SO_K:

この質問のバリエーションを何度も目にしたので、Q&Aを書こうと思いました。

DynamoDBの基本

これを読む前に、次のことを理解しておく必要があります。

  • すべてのDynamoDBテーブルには一意の主キーがあります
  • 主キーはパーティションキー構成する必要があり、オプションでソートキーを持つことができますパーティションキーとソートキーの両方を持つ主キーは、複合キーです。
  • A のGetItemの要求は、1とそのユニークなプライマリキーを使用して一つだけのアイテムを返します。
  • A クエリは、高速検索を行い、唯一つのパーティションキーを指定する必要があります。複数のアイテムを返すことができます。
  • A スキャンは、テーブル内のすべての項目を評価し、フィルタパラメータに基づいて、サブセットを返すことができます。スキャンは状況によっては正しい選択ですが、誤って使用すると、時間がかかり、コストがかかる可能性があります。
  • グローバルセカンダリインデックス(GSI)には、ベーステーブルとは異なるパーティションキーがあります。2つのテーブル(ベーステーブルとGSI)が同期されているようなものだと少し考えてください。用途によっては、GSIによってベーステーブルのコストが2倍になる場合があります。
  • ローカルセカンダリインデックス(LSI)は、ベーステーブルと同じパーティションキーを持ちますが、ソートキーが異なります。ベーステーブルデータを並べ替える別の方法と考えてください。ただし、パーティションキー内のみです。LSIは何の費用もかかりません。

1対1


パスポートと人をモデル化して、この関係を実証できます。1つのパスポートは1人の所有者のみを持つことができ、1人は1つのパスポートしか持つことができません。

アプローチは非常に簡単です。2つのテーブルがあり、それらのテーブルの1つに外部キーが必要です。

パスポートテーブル:

パーティションキー:PassportId

╔════════════╦═══════╦════════════╗
║ PassportId ║ Pages ║   Issued   ║
╠════════════╬═══════╬════════════╣
║ P1         ║    15 ║ 11/03/2009 ║
║ P2         ║    18 ║ 09/02/2018 ║
╚════════════╩═══════╩════════════╝

パスポートホルダーテーブル:

パーティションキー:PersonId

╔══════════╦════════════╦══════╗
║ PersonId ║ PassportId ║ Name ║
╠══════════╬════════════╬══════╣
║ 123      ║ P1         ║ Jane ║
║ 234      ║ P2         ║ Paul ║
╚══════════╩════════════╩══════╝

PersonIdがパスポートテーブルに表示されていないことに注意してください。そうすると、2つの場所に同じ情報(どのパスポートがどの人のものか)が表示されます。これにより、テーブルがどのパスポートの所有者であるかについて合意しなかった場合、追加のデータ更新と潜在的にいくつかのデータ品質の問題が発生します。

ただし、ユースケースがありません。PersonIdで個人を簡単に検索し、所有しているパスポートを見つけることができます。しかし、PassportIdがあり、それを所有している人を見つける必要がある場合はどうでしょうか。現在のモデルでは、パスポートホルダーテーブルでスキャンを実行する必要があります。これが通常の使用例である場合、スキャンを使用する必要はありません。GetItemをサポートするには、GSIをPassportホルダーテーブルに追加するだけです

パスポートホルダーテーブルGSI:

パーティションキー:PassportId

╔════════════╦══════════╦══════╗
║ PassportId ║ PersonId ║ Name ║
╠════════════╬══════════╬══════╣
║ P1         ║ 123      ║ Jane ║
║ P2         ║ 234      ║ Paul ║
╚════════════╩══════════╩══════╝

これで、PassportIdまたはPersonIdを使用して、非常に迅速かつ安価に関係を検索できます。

これをモデル化するための他のオプションがあります。たとえば、外部キーのない「プレーン」なPassportテーブルとPersonテーブルを作成し、次にPassortIdsとPersonIdsを単純にマッピングする3番目の補助テーブルを作成できます。この場合、それが最もクリーンなデザインだとは思わないが、もし望むなら、そのアプローチには何の問題もない。これらは多対多関係セクションの補助関係テーブルの例であることに注意してください。


1対多


ペットと飼い主をモデル化して、この関係を実証できます。ペットの飼い主は1人だけですが、飼い主は多くのペットを持つことができます。

モデルは1対1モデルと非常によく似ているため、この違いにのみ焦点を当てます。

ペットテーブル:

パーティションキー:PetId

╔═══════╦═════════╦════════╗
║ PetId ║ OwnerId ║ Type   ║
╠═══════╬═════════╬════════╣
║ P1    ║ O1      ║ Dog    ║
║ P2    ║ O1      ║ Cat    ║
║ P3    ║ O2      ║ Rabbit ║
╚═══════╩═════════╩════════╝

所有者テーブル:

パーティションキー:OwnerId

╔═════════╦════════╗
║ OwnerId ║ Name   ║
╠═════════╬════════╣
║ O1      ║ Angela ║
║ O2      ║ David  ║
╚═════════╩════════╝

多くのテーブルに外部キーを置きます。逆の方法で行って、PetIdをOwnerテーブルに入れると、1つのOwnerアイテムに一連のPetIdが必要になり、管理が複雑になります。

ペットの飼い主を見つけたい場合は、とても簡単です。我々は行うことができますGetItem関数をペットの項目を返すために、それは所有者が誰であるかを教えてくれる。しかし、逆の方法はより困難です。OwnerIdがある場合、どのペットが所有していますか?ペットテーブルでスキャンを実行する必要があるため、代わりにペットテーブルにGSIを追加します。

ペットテーブルGSI

パーティションキー:OwnerId

╔═════════╦═══════╦════════╗
║ OwnerId ║ PetId ║ Type   ║
╠═════════╬═══════╬════════╣
║ O1      ║ P1    ║ Dog    ║
║ O1      ║ P2    ║ Cat    ║
║ O2      ║ P3    ║ Rabbit ║
╚═════════╩═══════╩════════╝

OwnerIdがあり、そのペットを検索したい場合は、ペットテーブルGSIでクエリ実行できますたとえば、所有者O1に対するクエリは、PetId P1およびP2を持つアイテムを返します。

ここで何か面白いことに気づくかもしれません。主キーはテーブルに対して一意である必要があります。これは、ベーステーブルにのみ当てはまりますGSIプライマリキー(この場合はGSIパーティションキーのみ)は一意である必要はありません

DynamoDBテーブルでは、各キー値は一意である必要があります。ただし、グローバルセカンダリインデックスのキー値は一意である必要はありません

補足として、GSIはベーステーブルと同じ属性のすべて投影する必要はありませんルックアップのみにGSIを使用している場合は、GSIキー属性のみを投影したい場合があります。


多対多


DynamoDBで多対多の関係をモデル化するには、主に3つの方法があります。それぞれに長所と短所があります。

医師と患者の例を使用して、この関係をモデル化できます。医師は多くの患者を持つことができ、患者は多くの医師を持つことができます。


多対多-オプション1-補助テーブル


一般的に、これは私の推奨するアプローチです。アイデアは、関係参照のない「プレーン」ベーステーブルを作成することです。リレーションシップ参照は、補助テーブルに入れられます(リレーションシップタイプごとに1つの補助テーブル-この場合、Doctors-Patientsのみ)。

ドクターテーブル:

パーティションキー:DoctorId

╔══════════╦═══════╗
║ DoctorId ║ Name  ║
╠══════════╬═══════╣
║ D1       ║ Anita ║
║ D2       ║ Mary  ║
║ D3       ║ Paul  ║
╚══════════╩═══════╝

患者テーブル

パーティションキー:PatientId

╔═══════════╦═════════╦════════════╗
║ PatientId ║ Name    ║ Illness    ║
╠═══════════╬═════════╬════════════╣
║ P1        ║ Barry   ║ Headache   ║
║ P2        ║ Cathryn ║ Itchy eyes ║
║ P3        ║ Zoe     ║ Munchausen ║
╚═══════════╩═════════╩════════════╝

DoctorPatientテーブル(補助テーブル)

パーティションキー:DoctorId

ソートキー:PatientId

╔══════════╦═══════════╦══════════════╗
║ DoctorId ║ PatientId ║ Last Meeting ║
╠══════════╬═══════════╬══════════════╣
║ D1       ║ P1        ║ 01/01/2018   ║
║ D1       ║ P2        ║ 02/01/2018   ║
║ D2       ║ P2        ║ 03/01/2018   ║
║ D2       ║ P3        ║ 04/01/2018   ║
║ D3       ║ P3        ║ 05/01/2018   ║
╚══════════╩═══════════╩══════════════╝

DoctorPatientテーブルGSI

パーティションキー:PatientId

ソートキー:DoctorId

╔═══════════╦══════════╦══════════════╗
║ PatientId ║ DoctorId ║ Last Meeting ║
╠═══════════╬══════════╬══════════════╣
║ P1        ║ D1       ║ 01/01/2018   ║
║ P2        ║ D1       ║ 02/01/2018   ║
║ P2        ║ D2       ║ 03/01/2018   ║
║ P3        ║ D2       ║ 04/01/2018   ║
║ P3        ║ D3       ║ 05/01/2018   ║
╚═══════════╩══════════╩══════════════╝

3つのテーブルがあり、DoctorPatient補助テーブルが興味深いテーブルです。

DoctorPatientベーステーブルの主キーは一意である必要があるため、DoctorId(パーティションキー)とPatientId(ソートキー)の複合キーを作成します。

DoctorIdを使用してDoctorPatientベーステーブルに対してクエリ実行し、Doctorが持つすべての患者を取得できます。

PatientIdを使用してDoctorPatient GSIでクエリ実行し、患者に関連付けられているすべての医師を取得できます。

このアプローチの長所は、テーブルを明確に分離できることと、単純なビジネスオブジェクトをデータベースに直接マップできることです。セットなどのより高度な機能を使用する必要はありません。

更新を調整する必要があります。たとえば、Patientを削除する場合は、DoctorPatientテーブルのリレーションシップも削除するように注意する必要があります。ただし、データ品質の問題が発生する可能性は、他のいくつかのアプローチと比較して低いです。

編集:DynamoDBはTransactionsをサポートするようになり、複数の更新を複数のテーブルにまたがる単一のアトミックトランザクションに調整できるようになりました。

このアプローチの潜在的な弱点は、3つのテーブルを必要とすることです。スループットでテーブルをプロビジョニングする場合、テーブルが多いほど、容量を分散する必要があるシンが少なくなります。ただし、新しいオンデマンド機能では、これは問題ではありません。


多対多-オプション2-外部キーセット


このアプローチでは、2つのテーブルのみを使用します。

ドクターテーブル:

パーティションキー:DoctorId

╔══════════╦════════════╦═══════╗
║ DoctorId ║ PatientIds ║ Name  ║
╠══════════╬════════════╬═══════╣
║ D1       ║ P1,P2      ║ Anita ║
║ D2       ║ P2,P3      ║ Mary  ║
║ D3       ║ P3         ║ Paul  ║
╚══════════╩════════════╩═══════╝

患者テーブル:

パーティションキー:PatientId

╔═══════════╦══════════╦═════════╗
║ PatientId ║ DoctorIds║  Name   ║
╠═══════════╬══════════╬═════════╣
║ P1        ║ D1       ║ Barry   ║
║ P2        ║ D1,D2    ║ Cathryn ║
║ P3        ║ D2,D3    ║ Zoe     ║
╚═══════════╩══════════╩═════════╝

このアプローチでは、関係を各テーブルにセットとして保存します。

DoctorのPatientsを見つけるには、DoctorテーブルでGetItemを使用してDoctorアイテムを取得できます。次に、PatientIdは、Doctor属性にセットとして格納されます。

患者の医師を検索するには、PatientテーブルでGetItemを使用して、Patientアイテムを取得できます。次に、DoctorIdsがセットとして患者属性に格納されます。

このアプローチの長所は、ビジネスオブジェクトとデータベーステーブルの間に直接マッピングがあることです。テーブルは2つしかないので、プロビジョニングスループット容量を使用している場合は、薄く分散する必要はありません。

このアプローチの主な欠点は、データ品質の問題の可能性です。患者を医師にリンクする場合、各テーブルに1つずつ、2つの更新を調整する必要があります。1つの更新が失敗した場合はどうなりますか?データが同期しなくなる可能性があります。

もう1つの欠点は、両方のテーブルでのセットの使用です。DynamoDB SDKはセットを処理するように設計されていますが、セットが含まれる場合、特定の操作が複雑になる可能性があります。


多対多-オプション3-グラフスキーマ


AWSではこれまで、これを隣接リストパターンと呼んでいましたより一般的には、グラフデータベースまたはトリプルストアと呼ばれます

私は以前、AWS Adjanceyリストパターンでこの質問回答しました。これは、一部の人々がそれを理解するのに役立ったようです。

そして、AWSによる最近のプレゼンテーションで、このパターンについてここで詳しく説明しています

このアプローチでは、すべてのデータを1つのテーブルに格納します。

テーブル全体ではなく、いくつかのサンプル行を描画しました。

パーティションキー:Key1

ソートキー:Key2

╔═════════╦═════════╦═══════╦═════════════╦══════════════╗
║ Key1    ║ Key2    ║ Name  ║   illness   ║ Last Meeting ║
╠═════════╬═════════╬═══════╬═════════════╬══════════════╣
║ P1      ║ P1      ║ Barry ║ Headache    ║              ║
║ D1      ║ D1      ║ Anita ║             ║              ║
║ D1      ║ P1      ║       ║             ║ 01/01/2018   ║
╚═════════╩═════════╩═══════╩═════════════╩══════════════╝

そして、キーを反転するGSIが必要です。

パーティションキー:Key2

ソートキー:Key1

╔═════════╦═════════╦═══════╦═════════════╦══════════════╗
║ Key2    ║ Key1    ║ Name  ║   illness   ║ Last Meeting ║
╠═════════╬═════════╬═══════╬═════════════╬══════════════╣
║ P1      ║ P1      ║ Barry ║ Headache    ║              ║
║ D1      ║ D1      ║ Anita ║             ║              ║
║ P1      ║ D1      ║       ║             ║ 01/01/2018   ║
╚═════════╩═════════╩═══════╩═════════════╩══════════════╝

このモデルには、特定の状況でいくつかの長所があります-高度に接続されたデータでうまく機能します。データを適切にフォーマットすると、非常に高速でスケーラブルなモデルを実現できます。スキーマやテーブルを更新せずに、エンティティや関係をテーブルに保存できるという点で柔軟性があります。スループット容量をプロビジョニングする場合は、アプリケーション全体のすべての操作ですべてのスループットを利用できるため、効率的です。

このモデルは、誤って使用したり、真剣に検討しなかったりすると、いくつかの大きな欠点に悩まされます。

ビジネスオブジェクトとテーブルの間の直接マッピングはすべて失われます。これにより、ほとんどの場合、スパゲッティコードが読めなくなります。単純なクエリでも、非常に複雑に感じる場合があります。コードとデータベースの間に明確なマッピングがないため、データ品質の管理は困難になります。このアプローチを使用するほとんどのプロジェクトは、データベースを管理するためだけにさまざまなユーティリティを作成し、その一部は独自の製品になります。

もう1つの小さな問題は、モデル内のすべてのアイテムのすべての属性が1つのテーブルに存在する必要があることです。これは通常、何百もの列を持つテーブルになります。それ自体は問題ではありませんが、多くの列を持つテーブルで作業しようとすると、通常、データの表示が困難になるなどの単純な問題が発生します。

要するに、AWSはおそらく一連の記事の中で有用な記事をリリースしたと思いますが、多対多の関係を管理するためのその他の(より単純な)概念を導入できなかったため、多くの人々が混乱しました。したがって、明確にするために、隣接リストパターンは有用ですが、DynamoDBで多対多の関係をモデル化するための唯一のオプションではありません真剣にビッグデータなどの状況で機能する場合は、ぜひ使用してください。そうでない場合は、より単純なモデルの1つを試してください。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

不要なモデルを作成せずに、モデルファクトリ、1対1および1対多の関係でLaravel外部キーを定義する

分類Dev

1対多および1対多の関係1laravel

分類Dev

EntityFrameworkの1対多および多対多の関係

分類Dev

Djangoモデルで1対多の関係を追加する

分類Dev

hybris-1対多および多対多の関係

分類Dev

MongoDBの1対多および多対1の関係

分類Dev

データベースの関係に1対1および1対多でアクセスする

分類Dev

エンティティが1対多および多対多の関係を持つdynamodbのデータモデリング

分類Dev

1対多および多対多の関係を持つJOOQポジョ

分類Dev

Spring Boot ProjectでのMongoDBの1対多および多対1の関係

分類Dev

sql列間の1対多および1対1の関係

分類Dev

同じモデルのペアとの1対1および多対1の関係

分類Dev

Java / IntelliJで1つのクラスから別のクラスに1対多および多対1の関係を作成する方法

分類Dev

データベースで1対多の関係をモデル化する方法

分類Dev

Hibernateで1対多の関係をモデル化するための最良の方法

分類Dev

DynamoDBの1対多および多対多の構造

分類Dev

SQLServerで1対多および多対多の関係を持つ3つのテーブルを結合する

分類Dev

コードで多対多の関係をモデル化する方法は?

分類Dev

既存のモデルとdjangoで多対1の関係を作成する

分類Dev

hibernateを使用した1対多および1対1の関係

分類Dev

同じモデル間の多対多および1対多の関連付け

分類Dev

Slick 3.0.0:1対多/多対多の関係をクエリする方法

分類Dev

mirage jsで多形の1対1の関係を持つモデルをシードする方法は?

分類Dev

tableViewとレルムを使用して1対多の関係(親子)を作成および保存する方法

分類Dev

TypeORM:1対多および多対1の関係があるときに参加する

分類Dev

Solrで多対1の関係を表現および照会するための標準的な方法

分類Dev

最初にコード内の2つのエンティティ間の多対多および1対多の関係を定義する方法は?

分類Dev

1対1、1対多、および多対多の関係パフォーマンスの計算

分類Dev

GraphQLスキーマに1対多および多対多の関係を実装するにはどうすればよいですか?

Related 関連記事

  1. 1

    不要なモデルを作成せずに、モデルファクトリ、1対1および1対多の関係でLaravel外部キーを定義する

  2. 2

    1対多および1対多の関係1laravel

  3. 3

    EntityFrameworkの1対多および多対多の関係

  4. 4

    Djangoモデルで1対多の関係を追加する

  5. 5

    hybris-1対多および多対多の関係

  6. 6

    MongoDBの1対多および多対1の関係

  7. 7

    データベースの関係に1対1および1対多でアクセスする

  8. 8

    エンティティが1対多および多対多の関係を持つdynamodbのデータモデリング

  9. 9

    1対多および多対多の関係を持つJOOQポジョ

  10. 10

    Spring Boot ProjectでのMongoDBの1対多および多対1の関係

  11. 11

    sql列間の1対多および1対1の関係

  12. 12

    同じモデルのペアとの1対1および多対1の関係

  13. 13

    Java / IntelliJで1つのクラスから別のクラスに1対多および多対1の関係を作成する方法

  14. 14

    データベースで1対多の関係をモデル化する方法

  15. 15

    Hibernateで1対多の関係をモデル化するための最良の方法

  16. 16

    DynamoDBの1対多および多対多の構造

  17. 17

    SQLServerで1対多および多対多の関係を持つ3つのテーブルを結合する

  18. 18

    コードで多対多の関係をモデル化する方法は?

  19. 19

    既存のモデルとdjangoで多対1の関係を作成する

  20. 20

    hibernateを使用した1対多および1対1の関係

  21. 21

    同じモデル間の多対多および1対多の関連付け

  22. 22

    Slick 3.0.0:1対多/多対多の関係をクエリする方法

  23. 23

    mirage jsで多形の1対1の関係を持つモデルをシードする方法は?

  24. 24

    tableViewとレルムを使用して1対多の関係(親子)を作成および保存する方法

  25. 25

    TypeORM:1対多および多対1の関係があるときに参加する

  26. 26

    Solrで多対1の関係を表現および照会するための標準的な方法

  27. 27

    最初にコード内の2つのエンティティ間の多対多および1対多の関係を定義する方法は?

  28. 28

    1対1、1対多、および多対多の関係パフォーマンスの計算

  29. 29

    GraphQLスキーマに1対多および多対多の関係を実装するにはどうすればよいですか?

ホットタグ

アーカイブ