Voicyアドベントカレンダー 25日目の記事です。
今日は12月25日クリスマス、もう直ぐ今年も終わりですね。
このアドベントカレンダーも今日で最後となります。25日間のブログぜひ再度目を通していただけますと幸いです。
またVoicyではvoi-chordという声で届けるテックチャンネルもやっておりますので、ぜひそちらもお聞きください。
前置きが長くなりましたが、本題に入ります。
近頃データストアとしてRDBMSではなくNoSQLという選択をすることが自分やチームにおいて増えてきました。
しかし、DB設計にあたってRDSと構造が大きく異なることから、様々な壁にぶち当たってきました。
今回はそのNoSQLの代表格であるAWSDynamoDBをテーマに、その設計で得た知見を共有していきたいと思います。
RDSとDynamoDB(NoSQL)の設計における相違点
まずはRDBMSとDynamoDBの設計の違いについてまとめます
RDBMS
Dynamo DB
- クエリの柔軟性は低く、コストも低い
- ユースケースの詳細に設計が大きく関係する(クエリに合わせて設計を行う)
- キャパシティユニットの最適化のためできるだけ少ないテーブルを維持するべき
RDBMS の場合は、アクセスパターンを考慮せずに正規化されたデータモデルを作成できます。その後、新しいクエリの要件が発生したら、そのデータモデルを拡張することができます。しかし、DynamoDB の場合はビジネスロジックが明確になってから設計すべきものになります。
設計の手順
上記の特徴からDynamoDBの設計をする際は必要なビジネスロジックを明確化して、取得クエリから考える必要があります。
- ビジネスロジックを明確化する
- 取得する値やキーを考える(クエリを決定)
- テーブルの設計をする
キーの設計
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アドベントカレンダーの記事、良記事もたくさんありますので、ぜひご覧ください。
ぜひ良い年末年始をお過ごしください。 来年もよろしくお願いいたします。
参考文献
DynamoDB 用の NoSQL 設計 - Amazon DynamoDB
【AWS Black Belt Online Seminar】Amazon DynamoDB Advanced Design Pattern - YouTube