DynamoDBの設計において注意したいポイント

Voicyアドベントカレンダー 25日目の記事です。

今日は12月25日クリスマス、もう直ぐ今年も終わりですね。

このアドベントカレンダーも今日で最後となります。25日間のブログぜひ再度目を通していただけますと幸いです。

qiita.com

またVoicyではvoi-chordという声で届けるテックチャンネルもやっておりますので、ぜひそちらもお聞きください。

voicy.jp

前置きが長くなりましたが、本題に入ります。

近頃データストアとしてRDBMSではなくNoSQLという選択をすることが自分やチームにおいて増えてきました。

しかし、DB設計にあたってRDSと構造が大きく異なることから、様々な壁にぶち当たってきました。

今回はそのNoSQLの代表格であるAWSDynamoDBをテーマに、その設計で得た知見を共有していきたいと思います。

RDSとDynamoDB(NoSQL)の設計における相違点

まずはRDBMSとDynamoDBの設計の違いについてまとめます

RDBMS

  • 柔軟にクエリができるがコストが高い
  • ユースケースの詳細に設計が大きく関係しない
  • クエリ最適化がスキーマ設計に大きく関係しないが、正規化が重要

Dynamo DB

  • クエリの柔軟性は低く、コストも低い
  • ユースケースの詳細に設計が大きく関係する(クエリに合わせて設計を行う)
  • キャパシティユニットの最適化のためできるだけ少ないテーブルを維持するべき

RDBMS の場合は、アクセスパターンを考慮せずに正規化されたデータモデルを作成できます。その後、新しいクエリの要件が発生したら、そのデータモデルを拡張することができます。しかし、DynamoDB の場合はビジネスロジックが明確になってから設計すべきものになります。

設計の手順

上記の特徴からDynamoDBの設計をする際は必要なビジネスロジックを明確化して、取得クエリから考える必要があります。

  1. ビジネスロジックを明確化する
  2. 取得する値やキーを考える(クエリを決定)
  3. テーブルの設計をする

キーの設計

Amazon DynamoDB テーブルの各項目を一意に識別する主キーは、パーティションキーのみ、またはパーティションキーとソートキーの組み合わせになります。(ユニークキー同じものをInsertするとUpdateになる)

また、ここでキーとして設定したもの以外の値で取得する際にはフルスキャンという形になってしまいコストが高くなってため、セカンダリインデックスを用いる必要があります。

セカンダリインデックス

DynamoDB の各テーブルには、最大で20のグローバルセカンダリインデックスと5つのローカルセカンダリインデックスを持つことができます。

一般的に制限などがあるため、ローカルセカンダリインデックスではなく、グローバルセカンダリインデックスを使用するのが推奨されています。

グローバルセカンダリインデックス

パーティションキーおよびソートキーを持つインデックス。グローバルセカンダリインデックスにはサイズの制限はなく、読み込みアクティビティと書き込みアクティビティ用にプロビジョニングされた独自のスループット設定がテーブルのものとは異なります。

ローカルセカンダリインデックス

パーティションキーはベーステーブルと同じですが、ソートキーが異なるインデックス。パーティションキーが同一で属性情報を用いて検索を行いたい場合などに利用。パーィションキーバリューに対してインデックスが作成された項目の合計サイズが、10 GBに制限。

これらのインデックスは作成数にも上限がありますが、インデックスを効率的に使用するためにインデックス数は最小限に抑えることが推奨されています。 インデックスのを増やすことはストレージおよび I/O のコスト増大の一因になるためです。

DyamoDB設計のTips

最後に設計において知っておきたいTipsを紹介したいと思います。

  • Attributeの結合

複数のAttributeを組み合わせることで一つのキーを作成することです。 例えば注文テーブルにおいて、購入日と購入ステータスそれぞれをフィルタしたい場合にStatusDateのようなキー名でセカンダリインデックスを作成し、データとしていれるものは「ステータス_購入日」のような結合したものにします。そしてクエリをする際はBEGINWITHのような公文を用いることでフィルタよりも効率的に取得することが可能になります。

  • スパースインデックス

特定Itemにしか設定していない項目にGSIを含めることでプライマリーキー、ソートキー以外のキーでデータ抽出を容易にします。 例えば購入テーブルがあり、返金日のようなものは特定のデータにしか存在しない場合に、そのカラムをプライマリキーにしてグローバルセカンダリインデックスを設定することで高コストなscanを防ぐことができます。

  • GSI OVERLOADING

グローバルセカンダリインデックスの多重定義とも呼ばれます。 Dynamo DBの設計において推奨されるテーブル数を少なくしたい場合やクエリ対象が増えてグローバルセカンダリインデックスを増やしたくない場合に用いると良いテクニックです。 一つのグローバルセカンダリインデックスに複数の検索条件を持たせることで実現します。 例えば以下のようなRDBMSのテーブルをNoSQLに移行する場合、それぞれの属性に対して検索をかけたい場合があるとします。

ID name date address
1 name1 2021-01-01 foo
2 name2 2021-01-01 bar

その場合Dynamoでは以下のように定義することで各値で検索することができます

  • テーブル
ID(p key) type(s key) value
1 name name1
1 date 2021-01-01
1 address foo
value(p key) ID(s key) type
name1 1 name
2021-01-01 1 date
foo 1 address

※もちろんテーブル構成が複雑になりデータの可視化などに影響があるので 積極的に使用できるものではありません

まとめ

最後までお読みいただきありがとうございました。

最後に繰り返しになりますが、Voicyの2021アドベントカレンダーの記事、良記事もたくさんありますので、ぜひご覧ください。

qiita.com

ぜひ良い年末年始をお過ごしください。 来年もよろしくお願いいたします。

参考文献

DynamoDB 用の NoSQL 設計 - Amazon DynamoDB

【AWS Black Belt Online Seminar】Amazon DynamoDB Advanced Design Pattern - YouTube