Open5

キーバリュー型データストアの設計

ふじしろふじしろ

概要確認

DynamoDBのテーブル設計は、リレーショナルデータベース(RDB)とは異なるアプローチが必要です。リレーショナルデータベースでは、テーブルを正規化し、ジョインを使ってデータを組み合わせますが、DynamoDBでは、非正規化や単一テーブル設計が一般的です。
DynamoDBの設計における主な考慮事項は以下の通りです。
1. アクセスパターンの理解: DynamoDBのテーブル設計は、使用するアクセスパターンをしっかり理解し、それに基づいて行うことが重要です。読み取りと書き込みの操作をどのように行うか、どのようなデータを取得するかなどの情報が設計の根幹になります。
2. パーティションキーとソートキーの選択: DynamoDBでは、パーティションキーとソートキーを設定し、それに基づいてデータが配置されます。パーティションキーはデータの分散を助けるため、できるだけユニークな値を選択することが推奨されます。ソートキーには、クエリでよく使用する属性を指定します。
3. インデックスの使用: DynamoDBでは、データの取得を効率化するために、インデックスを利用できます。セカンダリインデックスは、アプリケーションの異なるアクセスパターンに対応するために使用されます。

DynamoDB用語の確認
dynamodbの以下の用語がもつ概念やニュアンスが伝わるように詳しく解説

  • パーティションキー
  • ソートキー
  • 属性
1. パーティションキー:
パーティションキーは、DynamoDBテーブルのデータを一意に識別するために使用される主要な識別子です。別名「ハッシュキー」とも呼ばれます。パーティションキーの主な目的は、データの均一な分布を確保し、スケーラビリティとパフォーマンスを向上させることです。
DynamoDBは内部的にデータをパーティションに分割し、それぞれのパーティションは独立して読み書きが行われます。パーティション数は、テーブルの設定に基づいて自動的にスケールします。パーティションキーで指定された値に基づいて、データがどのパーティションに格納されるかが決定されます。そのため、パーティションキーの選択がパフォーマンスに大きく影響します。繰り返しになりますが、良いパーティションキーは、データをパーティション間で均等に分散できる一意の値です。
1. ソートキー:
ソートキーは、DynamoDBテーブルのデータを特定の順序で整列するために使用されます。別名「レンジキー」とも呼ばれます。ソートキーは、パーティションキーと組み合わせて、一意の複合主キーを形成します。つまり、ソートキーは単独ではデータの一意性を保証しないことに注意してください。
ソートキーを使用すると、パーティションキー内のデータを効率的にクエリできます。例えば、日付範囲や範囲内の特定の属性値を持つアイテムなど、特定の条件に一致するアイテムを取得するのに役立ちます。また、ソートキーを使ったクエリでは、昇順または降順で結果を取得できます。
1. 属性:
属性は、DynamoDBテーブル内の各データアイテム(レコード)に関連する情報です。リレーショナルデータベースのカラムに相当します。属性は、いくつかの異なるデータ型を持つことができます: 文字列、数値、バイナリデータ、ブール値、リストやマップなどのコレクション型。
DynamoDBでは、レコードごとに異なる属性を持つことができます。これは、スキーマレスデザインと呼ばれるもので、アプリケーションの柔軟性を向上させ、進化する要件に対応することが容易になります。ただし、全てのデータアイテムは、パーティションキーと任意で選択できるソートキーを持たなければなりません。他の属性については、必要に応じて任意の数を持つことができます。

DynamoDbはスキーマレスデザイン。
事前に属性(RDBでいうカラムに相当)を定義しておく必要はない。

DynamoDBはスキーマレスデザインを採用しているため、事前に属性(カラム)を定義しておく必要はありません。ですが、パーティションキーと任意で選択できるソートキーは必須です。これらは、データの分散と並べ替えのために使用される重要なキーです。
レコードを追加する際、必要な属性を指定してデータを格納できます。各レコードは独自の属性セットを持つことができ、属性の追加・削除、データ型の変更が柔軟に行えます。ただし、一貫性のためにアプリケーション側で属性の管理やバリデーションを行うことが重要です。
パーティションキーとソートキー以外の属性(カラム)をレコードに追加する際は、`put-item`や`update-item`コマンド、またはDynamoDB SDKを使用して操作できます。アイテムの属性を指定する場合、属性名とそのデータ型をキー・バリュー形式で記載します。例えば、`AttributeName`をキーにして、属性の値とデータ型を対にして指定します。

パーティションキー、ソートキー共にnullは非許容
// ソースを貼る

ふじしろふじしろ

Q:
GSIのプライマリキーに設定すべき属性を判断するにはどうすればよいですか

A:
グローバルセカンダリインデックス(GSI)のプライマリキーに設定する属性を決定する際には、アプリケーションのクエリパターンやデータアクセスの要件を慎重に考慮する必要があります。適切な属性を選択するためのいくつかのガイドラインは以下の通りです:

1. クエリパターンの分析

  • 頻繁に検索される属性:アプリケーションがよく使う検索条件である属性を選択します。
  • 特定の属性に基づくクエリ:特定の属性に基づいてデータを頻繁にフィルタリングする場合、その属性はGSIの良い候補です。

2. アクセスパターンの考慮

  • 読み取りと書き込みのバランス:GSIは書き込み時に追加コストがかかるため、読み取り操作が多いが書き込みが少ないデータセットに適しています。
  • データの分布:一様に分散しているデータセット(ホットスポットを避ける)でGSIを使用することが効果的です。

3. ビジネス要件の理解

  • アプリケーションのビジネスロジック:ビジネス上重要な属性や機能要件に基づいてGSIを構築することが重要です。
  • 将来のスケーラビリティ:将来的なデータの成長やアクセスパターンの変化を考慮してGSIを計画します。

4. パフォーマンスとコストの考慮

  • パフォーマンスの最適化:特定のクエリに対して高速なレスポンスが必要な場合、GSIはそのクエリを効率化するのに役立ちます。
  • コスト管理:GSIの使用は追加コストを発生させるため、コスト対効果を考慮する必要があります。

実践例

例えば、ユーザーデータベースでメールアドレスに基づいてユーザーを検索する必要がある場合、メールアドレス属性をGSIのプライマリキーとして設定するのが理にかなっています。これにより、メールアドレスに基づくクエリが高速化され、アプリケーションのパフォーマンスが向上します。

最終的には、アプリケーションの特定のニーズとデータアクセスパターンに基づいて、適切な属性を選択することが重要です。また、プロジェクトの進行に伴って、これらの要件が変化する可能性があるため、インデックスの選択も柔軟に調整する必要があります。

ふじしろふじしろ

Q:
GSIのプライマリーキーを設定するに当たり、
@DynamoDbBeamを付与したエンティティはKotlinでどのように定義すればよいか?

A:
DynamoDBのグローバルセカンダリインデックス(GSI)を利用するためには、Kotlinでエンティティクラスを定義し、@DynamoDbBean アノテーションを付与する必要があります。このエンティティクラスはDynamoDBのテーブル構造を表し、GSI用の属性も含めて定義されます。

以下は、GSIを持つDynamoDBテーブルに対応するエンティティの基本的な例です。この例では、email 属性をGSIのプライマリキーとして使用しています。

import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.*

@DynamoDbBean
class UserEntity {

    @get:DynamoDbPartitionKey
    var userId: String? = null

    @get:DynamoDbSortKey
    var userName: String? = null

    var age: Int? = null

    @get:DynamoDbSecondaryPartitionKey(indexNames = ["email-index"])
    var email: String? = null

    // その他の属性やメソッド
}

このクラス定義では、次のポイントに注意してください:

  1. @DynamoDbBean

    • このアノテーションはクラスがDynamoDBテーブルのエンティティであることを示します。
  2. プライマリキー

    • @DynamoDbPartitionKey@DynamoDbSortKey アノテーションで、それぞれパーティションキーとソートキーを指定します。
  3. セカンダリインデックスのキー

    • @DynamoDbSecondaryPartitionKey アノテーションを使用して、GSIのプライマリキーを指定します。indexNames プロパティには、その属性がプライマリキーとして使用されるGSIの名前を指定します。
  4. その他の属性

    • 他の属性(この例では age)は、通常のプロパティとして追加されます。

このエンティティクラスを使用して、DynamoDBテーブルに対する操作(クエリ、スキャン、挿入、更新など)を実行できます。GSIを活用するには、クエリ操作時に適切なインデックス名を指定する必要があります。