DynamoDBに請求書の明細を保存するテーブルを作成しようとしています。アイテムがCompanyCode
、InvoiceNumber
およびLineItemId
、金額、その他の広告申込情報の詳細で定義されているとします。
一意のアイテムは、最初の3つの属性の組み合わせによって定義されます。これらの属性のうち2つは、異なるアイテムに対して同じにすることができます。ハッシュ属性と範囲属性として何を選択すればよいですか?
@ georgeaf99が提供する最初のオプション は機能しません。そのようにすると、CompanyCode
はテーブル内で一意である必要があるためです。したがって、会社ごとに1つのアイテムしか許可されません。 2番目の解決策が唯一の現実的な方法だと思います。
ハッシュキーとしてCompanyCode
を使用できます。その後、アイテムを一意にするために結合する他のすべてのフィールド(この場合はInvoiceNumber
とLineItemId
)を何らかの方法1つの値(フィールドデリミタとの連結など)に結合され、これが範囲キーになります。残念ながら、これはthatいですが、それがDynamoDBのようなNoSQLデータベースの性質です。ただし、正しい一意性でレコードを正常に保存できます。レコードを読み戻すときに、結合されたフィールドを解析して個々の部分に戻したくない場合は、InvoiceNumber
とLineItemID
に個別のフィールドを追加する必要があります。
会社ごとに多数の請求書がない場合は、ハッシュキーのみでクエリを実行し、クライアント側でフィルタリングを実行できます。会社ごとに多数の請求書があり、単一の請求書のアイテムのみを照会できるようにする必要がある場合は、CompanyCodeとInvoiceNumberにセカンダリインデックスを作成します。
効率のために、まったく異なる設計を提案します。 NoSQLデータベース(およびDynamoDBに違いはありません)では、常に最初にアクセスパターンを考慮する必要があります。また、可能であれば、すべてのデータを同じテーブルといくつかのインデックスに収めるよう努力する必要があります。 OPから得たものと彼のコメントから、これらは2つのアクセスパターンです。
今、私たちは良い主キーとは何だろうか?良いパーティションキー(PK)とは何ですか?良いソートキー(SK)とは何か、どのセカンダリインデックスを作成する必要があり、どのような種類(ローカルまたはグローバル)なのかという質問に変換しますか?いくつかのリマインダー:
KeyConditionExpression
のオプションがあります。このオプションは、 ソート用の演算子のセット とその間のすべて(そのうちの1つは関数begins_with (a, substr)
)を提供しますFilterExpression
を使用することもできます(投影された属性をフィルタリングします)モデル化して同じテーブルに収める必要がある複数のエンティティを扱っていることは明らかです。パーティションキーがテーブル上で一意であるという条件を満たすために、CompanyCode
は自然なパーティションキーとして提供されるため、一意であることを確認します。そうでない場合、2番目のアクセスパターンをどのようにモデル化できますか?
CompanyCode
に一意性が確立されていると仮定して、単純化して、電子メールの形式(またはドメインまたは単なるコードですが、デモには電子メールを使用します)であるとしましょう。
CompanyCode
であり、SKがInvoiceNumber
である場合、その会社の請求書に関するすべての属性を格納できます。Customer
であるレコードを追加することを妨げるものはありません。これにより、会社に関するすべての属性を格納できます。InvoiceNumber
)で、GSI1SKがテーブルPK(CompanyCode
)である逆ルックアップを作成します。LineItemId
で、SKがCompanyCode
である広告申込情報を保存しています(まだ一意です)InvoiceNumber
であり、GSI1SKはテーブルPKであるLineItemId
であるため、請求書エンティティアイテムの場合と同じです。これでサポートされるアクセスパターン:
CompanyCode=X
のテーブルを照会し、=
演算子でKeyConditionExpression
のソートキーを使用してInvoiceNumber
を使用します。その請求書に関連付けられているすべてのアイテムを取得する場合は、Items
を使用してProjectionExpression
属性を投影します。BatchGetItem
API呼び出し(一意の複合キーLineItemId+CompanyCode
を使用)を実行し、その特定の顧客の特定の請求書に属するすべてのアイテムを取得できるようになりました。 (これには BatchGetItem API の制約がいくつかあります)CompanyCode=X
を使用してクエリを実行し、SKでKeyConditionExpression
をbegins_with (a, substr)
関数/演算子で使用して、会社Xの請求書のみを取得し、その会社のメタデータは取得しません。これにより、特定の会社/顧客のすべての請求書が提供されます。InvoiceNumber
について、その特定の請求書に属するすべての品目を簡単に選択できます。 REMEMBER:グローバルセカンダリインデックスのキー値は一意である必要はありません -したがって、GSI1では簡単にinvoice_1->(item_1、item_2)、次に別のinvoice_1->(item_1、item_2)ですが、GSIの2つのアイテムの違いはSKにあります(異なるCompanyCode
に関連付けられます(ただし、デモンストレーションのためにinvoice_1とinvoice_2)。わかっていると思いますが、主キー(ハッシュ+範囲)から3つ以上の属性を持つことはできません。したがって、実行するクエリのタイプとデータのサイズに応じて、さまざまな方法でテーブルを構築できます。
(上記のクエリタイプ用に最適化:CompanyCode
と3つのみ)
小規模/中規模のデータセットに最適なソリューション:
CompanyCode
CompanyCode
のみを使用してクエリを実行し、他の2つの属性で結果をフィルタリングします大規模なデータセットに最適なソリューション:
CompanyCode
InvoiceNumber
+ LineItemId