web-dev-qa-db-ja.com

常にハッシュと範囲の主キータイプを使用してDynamoDBテーブルを作成する必要がありますか?

ドキュメント( http://docs.aws.Amazon.com/amazondynamodb/latest/developerguide/APISummary.html )には、次のように記載されています。

主キーがハッシュアンドレンジタイプのテーブルのみをクエリできます

そして

クエリ操作をほとんど使用できるようにアプリケーションを設計し、必要な場合にのみスキャンを使用することをお勧めします

直接述べられていませんが、これにより、ハッシュと範囲の主キーを使用することがベストプラクティスになりますか?

編集:

回答TL; DR:データモデルに適した主キータイプを使用し、クエリサポートを向上させるためにセカンダリインデックスを使用します。

参照:

http://docs.aws.Amazon.com/amazondynamodb/latest/developerguide/GSI.html

http://www.allthingsdistributed.com/2013/12/dynamodb-global-secondary-indexes.html

https://forums.aws.Amazon.com/thread.jspa?messageID=604862

どのような状況でDynamoDBでシンプルハッシュキーを使用しますか?

11
Brett

使用するキーの選択は、特定のシナリオのユースケースとデータ要件によって決まります。たとえば、ユーザーセッションデータを保存している場合、各レコードを参照できるため、範囲キーを使用してもあまり意味がない場合があります。 GUIDで、グループ化の要件なしで直接アクセスします。一般的に、セッションIDがわかれば、キーでクエリを実行する特定のアイテムを取得できます。別の例として、ユーザーアカウントまたはプロファイルデータの保存があります。 、各ユーザーには独自のユーザーがあり、ほとんどの場合、(ユーザーIDまたはその他の方法で)直接アクセスします。

ただし、Order Itemsを保存している場合は、Range Keyの方がはるかに理にかなっています。これは、次のようにグループ化されたアイテムを取得するためです。彼らの注文

データモデルに関して、ハッシュキーを使用すると、テーブルからレコードを一意に識別でき、範囲キーは、オプションで、通常は一緒に取得される複数のレコードをグループ化およびソートするために使用できます。例:注文アイテムを保存する集計を定義している場合、注文IDになります。ハッシュキー、およびOrderItemId範囲キー。特定の注文から注文アイテムを検索する場合は常に、ハッシュキー(注文ID)でクエリを実行します。そして、あなたはすべての注文アイテムを手に入れます。

これらの2つのキーの使用に関する正式な定義を以下に示します。

「範囲キーを使用した複合ハッシュキーを使用すると、開発者は、「ハッシュ属性」と「範囲属性」の2つの属性を組み合わせた主キーを作成できます。複合キーに対してクエリを実行する場合、ハッシュ属性は一意に一致する必要がありますが、範囲属性には範囲操作を指定できます。たとえば、過去24時間のWernerからのすべての注文、または過去24時間に個々のプレーヤーがプレイしたすべてのゲーム時間。" [VOGELS]

したがって、範囲キーデータモデルにグループ化機能を追加しますが、これら2つのキーの使用はストレージモデル

「Dynamoはコンシステントハッシュを使用して、レプリカ全体でキースペースを分割し、均一な負荷分散を保証します。均一なキー分散は、キーのアクセス分散が大きく偏っていないと仮定すると、均一な負荷分散を実現するのに役立ちます。」 [DDB-SOSP2007]

ハッシュキーを使用すると、レコードを一意に識別できるだけでなく、負荷分散を保証するメカニズムもあります。 範囲キー(使用する場合)は、ほとんど一緒に取得されるレコードを示すのに役立ちます。したがって、ストレージはそのようなニーズに合わせて最適化することもできます。

データを表す正しいキーを選択することは、設計プロセスにおける最も重要な側面の1つであり、アプリケーションのパフォーマンス、拡張性、およびコストに直接影響します。


脚注:

  • データモデルは、データを認識して操作するためのモデルです。データベース[FOWLER]のデータとどのようにやり取りするかについて説明します。つまり、データモデルを抽象化する方法、エンティティをグループ化する方法、主キーとして選択する属性などです。

  • ストレージモデルは、データベースがデータを内部的に保存および操作する方法を説明します[FOWLER]。これを直接制御することはできませんが、データベースが内部でどのように機能するかを知ることで、データの取得方法または書き込み方法を確実に最適化できます。

13
bsd

必ずしも。ユースケースのアクセスパターンをサポートする主キーを選択するのが最善です。

たとえば、sersのテーブルが必要だとします。 1人のユーザーの詳細(名前、電子メール、作成者など)を保存します。アクセスパターンは、特定のユーザーの詳細を取得している可能性があります。この場合、タイプhashの主キーを、serIdのハッシュキーとともに使用する方が理にかなっています。

Groupsを格納する別のテーブルも必要だとします。アクセスパターンは、特定のグループのすべてのメンバーを取得することです。ここでは、タイプハッシュと範囲の主キーを使用する方が理にかなっています。ハッシュキーと範囲キーはそれぞれgroupIdserIdです。

知っておくべき重要なことは、 両方のキータイプの違い (以下の引用)と テーブルの操作に関するガイドライン です。

  • ハッシュタイプ主キー-主キーは、ハッシュ属性という1つの属性で構成されています。 DynamoDBは、これに順序付けられていないハッシュインデックスを構築します
    主キー属性。表の各項目は一意に識別されます
    ハッシュキー値による。

  • ハッシュおよび範囲タイプの主キー-主キーは2つの属性で構成されています。最初の属性はハッシュ属性で、2番目の属性はハッシュ属性です
    1つは範囲属性です。 DynamoDBは順序付けられていないハッシュインデックスを構築します
    ハッシュ主キー属性、およびソートされた範囲インデックス
    範囲の主キー属性。表の各項目は一意です
    ハッシュと範囲キー値の組み合わせによって識別されます。 2つのアイテムが同じハッシュキー値を持つことは可能ですが、それらの2つのアイテムは異なる範囲キー値を持つ必要があります。

Dynamo DBでベストプラクティスの詳細を確認できます テーブルの操作に関するガイドラインのドキュメント

5
mkobit

他の人がすでに言ったように-いいえ、あなたはすべきではありません。

混乱して、そもそもこの質問をする原因となったステートメントは間違った

主キーがハッシュアンドレンジタイプのテーブルのみをクエリできます

主キーが単一属性(パーティションのみ)タイプのテーブルをクエリできます。

証明:

# Create single-attribute primary key table
aws dynamodb create-table --table-name testdb6 --attribute-definitions '[{"AttributeName": "Id", "AttributeType": "S"}]' --key-schema '[{"AttributeName": "Id", "KeyType": "HASH"}]' --provisioned-throughput '{"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}' 

# Populate table
aws dynamodb put-item --table-name testdb6 --item '{ "Id": {"S": "1"}, "LastName": {"S": "Lopez"}, "FirstName": {"S": "Maria"}}'
aws dynamodb put-item --table-name testdb6 --item '{ "Id": {"S": "2"}, "LastName": {"S": "Fernandez"}, "FirstName": {"S": "Augusto"}}'

# Query table using only partition attribute
aws dynamodb query --table-name testdb6 --select ALL_ATTRIBUTES --key-conditions '{"Id": {"AttributeValueList": [{"S": "1"}], "ComparisonOperator": "EQ"}}'

最後のコマンドの出力(動作します):

{
"Count": 1,
"Items": [
    {
        "LastName": {
            "S": "Lopez"
        },
        "Id": {
            "S": "1"
        },
        "FirstName": {
            "S": "Maria"
        }
    }
],
"ScannedCount": 1,
"ConsumedCapacity": null
}
1
golem