✨
検索性の高いAmazon DynamoDBのテーブル設計
やりたいこと
Amazon DynamoDBはNoSQLデータベースサービスである。DynamoDBでは、パーティションキーやセカンダリーキーに対して完全一致もしくは前方一致のみでのデータ取得となる。そのためしかしRDSなどのリレーショナルデータベースと異なり、検索や並び替えなどに関して考慮した設計が必要となります。
以下の記事を参考に行った検索性の高いDynamoDBのテーブル設計について記載します。
設計
参考ページと同様にブログ記事を元に以下の内容になります。
ブログ ←投稿-ユーザー
↑
コメント
ER図の作成
テーブル設計
- できる限り1つのテーブルにまとめる
- PK-SKに対して1つのValueをもつ
- CRUDによるデータ取得を想定
Key-Valueの設定
- PK(パーティションキー)を
<エンティティ名>#<ID>
とする - SK(ソートキー)を
<エンティティ名>#<キー>
とする - GSI(グローバスセカンダリインデックス)を
<エンティティ名>
とする - Valueに各項目の値をもつ
ソートの設計
- PK(パーティションキー)を
<エンティティ名>#<ID>
とする - SK(ソートキー)を
<エンティティ名>#<ソート名>
とする - GSI(グローバスセカンダリインデックス)を
<エンティティ名>
とする - Value:<key><Value>#<ソート名><Value> とする(記事投稿順の場合、
author_<ユーザーID>#publishDt_<公開日>
)
(例)作成されるテーブル
PK | SK | Value |
---|---|---|
POST#aaaa-aaaa-aaaa | POST#aaaa-aaaa-aaaa | |
POST#aaaa-aaaa-aaaa | POST#title | タイトルA |
POST#aaaa-aaaa-aaaa | POST#content | 本文A |
POST#aaaa-aaaa-aaaa | POST#published_at | 2024-01-01 |
POST#aaaa-aaaa-aaaa | POST#sortPublishDtByAuthor | author_1111-1111-1111#publishDt_2024-01-01 |
POST#bbbb-bbbb-bbbb | POST#bbbb-bbbb-bbbb | |
POST#bbbb-bbbb-bbbb | POST#title | タイトルB |
POST#bbbb-bbbb-bbbb | POST#content | 本文B |
POST#bbbb-bbbb-bbbb | POST#published_at | 2024-01-02 |
POST#bbbb-bbbb-bbbb | POST#sortPublishDtByAuthor | author_1111-1111-1111#publishDt_2024-01-02 |
USER#aaaa-aaaa-aaaa | USER#user_id | |
USER#aaaa-aaaa-aaaa | USER#username | ユーザー名A |
USER#aaaa-aaaa-aaaa | USER#email | aaaa-aaaa-aaaa@example.com |
USER#aaaa-aaaa-aaaa | USER#created_at | 2024-01-01 |
COMMENT#aaaa-aaaa-aaaa | COMMENT#comment_id | |
COMMENT#aaaa-aaaa-aaaa | COMMENT#post_id | aaaa-aaaa-aaaa |
COMMENT#aaaa-aaaa-aaaa | COMMENT#user_id | aaaa-aaaa-aaaa |
COMMENT#aaaa-aaaa-aaaa | COMMENT#content | コメントA |
COMMENT#aaaa-aaaa-aaaa | COMMENT#published_at | 2024-01-02 |
データ取得
以下に各項目のデータ返却手順の案です。
POST一覧取得の手順
クエリ
GSI:post
その結果以下のレコードを取得
POST#aaaa-aaaa-aaaa / POST#aaaa-aaaa-aaaa
POST#aaaa-aaaa-aaaa / POST#title (タイトルA)
POST#aaaa-aaaa-aaaa / POST#content (本文A)
POST#aaaa-aaaa-aaaa / POST#sortPublishDt (publishDt_20210403)
POST#aaaa-aaaa-aaaa / POST#sortPublishDtByAuthor
POST#bbbb-bbbb-bbbb / POST#bbbb-bbbb-bbbb
...
PK毎に5つのレコードをまとめることで1つの記事のデータとして返却
POSTの手順
クエリ
PK: POST#aaaa-aaaa-aaaa
SK: begins_with('POST')
その結果以下のレコードを取得
POST#aaaa-aaaa-aaaa / POST#aaaa-aaaa-aaaa
POST#aaaa-aaaa-aaaa / POST#title (タイトルA)
POST#aaaa-aaaa-aaaa / POST#content (本文A)
POST#aaaa-aaaa-aaaa / POST#sortPublishDt (publishDt_20210403)
POST#aaaa-aaaa-aaaa / POST#sortPublishDtByAuthor
...
この5つのレコードをまとめることで1つの記事のデータとして返却
記事投稿順の取得
クエリ
SK:begin_with("author_1111-1111-1111#")
GSI:post
POST同様、PK毎にデータをまとめる
実際に利用してみて
これまでのやり方
これまでは以下のように同じIDを持つ内容が「複数のアイテムとして保存」していた。
PK | SK | ID | title | content | published_at |
---|---|---|---|---|---|
POST | aaaa-aaaa-aaaa | タイトルA | 本文A | 2024-01-01 |
- 検索などをデータベース設計時に想定する必要があった。
- 要件変更によって検索ができない場合、
scan
やfilter
などを行っていた。 - 必要な情報を取得するためにオーバーフェッチ的になっていた。
- ソート順をデータ取得後の処理で行う必要があった。
良かった点
- ER図を作成した時点でDB設計が完了できる。
- 要件変更があった場合も対応が比較的容易。
- データ取得時にソート処理ができる。
- DynamoDBの
scan
による負荷、コスト増を減らせる。
悪い点
- データ取得後にまとめる手間が生まれる
今後
GraphQLにおいても同様にデータ取得できるか確認したい。
Discussion