@mizumotokのブログ

テクノロジー、投資、書評、映画、筋トレなどについて

DynamoDBのテーブルを1つだけにする設計のコツ(汎用的手法編)

DynamoDBではテーブルを1つだけにすることが推奨されています。前回の投稿ではDynamoDBのテーブルを1つだけにする設計のコツを具体例を元に考えてみました。今回はどんな場合にでも通用するような汎用的な手法を考えてみます。

mizumotok.hatenablog.jp

f:id:mizumotok:20190813172249j:plain

エンティティにIDを追加

エンティティにはユニークなIDを持たせるのが普通です。
前回の例にIDを持たせたデータは以下のようになります。

Artistテーブル

ID ArtistName CarrerStart
1 David Bowie 1962
2 Bryan Adams 1975
3 Steely Dan 1972

Songテーブル

ID SongTitle Artist ID Released Album ID Note
1 Ziggy Stardust 1 1972 1 This is a good so...
2 Changes 1 1971 2
3 Sons of the Silent Age 1 1977 3
4 Heroes 1 1977 3 Good
5 Cloud Number Nine 2 1988 4
6 Summer of '69 2 1984 5
7 On a Day Like Today 2 1998 4
8 Reelin' in the Years 3 1972 6
9 Turn That Heartbeat Ov... 3 1972 6
10 Change of the Guard 3 1972 6
11 Deacon Blues 3 1977 7

Albumテーブル

ID AlubumTitle Artist ID Genre Studio
1 The Rise and Fall of Zi... 1 Rock Trident Studios
2 Hunky Dory 1 Rock Trident Studios
3 Heros 1 Rock Hansa
4 On a Day Like Today 2 Alternative The Warehous...
5 Reckless 2 Rock Little Mountain...
6 Can't Buy a Thrill 3 Soft Rock The Village Rec...
7 Aja 3 Soft Rock The Village Rec...

隣接関係のリスト設計パターン

隣接関係のリスト設計パターンを利用して、PK(パーティションキー)にエンティティID、SK(ソートキー)にリレーションのあるエンティティIDを入れます。
エンティティIDは[エンティティ名]-[ユニークなID]という形式にします。IDの採番はDynamoDBではオートインクリメントがUUIDを使えばいいです。putする前にそのIDが使われていないかはチェックする必要があります。

PK SK
Artist-1 Song-1
Artist-1 Song-2
Artist-1 Song-3
Artist-1 Song-4
Artist-1 Album-1
Artist-1 Album-2
Artist-1 Album-3
Artist-2 Song-5
Artist-2 Song-6
Artist-2 Song-7
Artist-2 Album-4
Artist-2 Album-5
Artist-3 Song-8
Artist-3 Song-9
Artist-3 Song-10
Artist-3 Song-11
Artist-3 Album-6
Artist-3 Album-7

グローバルセカンダリインデックスGSI1をテーブルのPKをプライマリキー、テーブルのSKをソートキーとして作ります。
こうすることで多対多の関係であっても、エンティティIDを指定することでリレーションのあるエンティティを取り出すことができるようになります。
例えば、テーブルのPK='Artist-1'、SK=begins_with('Song-')を指定すれば、Artist-1のSongを取り出すことができます。逆にGSI1のPK='Song-1'、SK=begins_with('Artist-')を指定すれば、Song-1のArtistを取りですことができます。

クエリの洗い出し

次にアプリケーションに使うクエリを考えます。
前回と同じく、以下のようなクエリーがアプリケーションに必要だとします。

  1. アーティスト名を指定してすべての曲を見つける
  2. ジャンルを指定してすべてのアルバムを見つける
  3. リリース年とアーティスト名から曲を検索する
  4. 曲名から同じ曲名の曲を検索する

グローバルセカンダリインデックスの多重定義

グローバルセカンダリインデックスの多重定義を利用します。

検索に使う項目をテーブルにSKに、その項目の値をDataカラムに入れます。
検索に使う項目は以下のとおりです。

  • Artistのアーティスト名
  • Albumのジャンル
  • Songのアーティスト名とリリース年
  • Songの曲名

SKに入れる項目名は[エンティティ名]_[項目名]という形式にします。

PK(GSI1のSK) SK(GSI1のPK) Data
Artist-1 Artist_Name David Bowie
Artist-1 Song-1
Artist-1 Song-2
Artist-1 Song-3
Artist-1 Song-4
Artist-1 Album-1
Artist-1 Album-2
Artist-1 Album-3
Artist-2 Artist_Name Bryan Adams
Artist-2 Song-5
Artist-2 Song-6
Artist-2 Song-7
Artist-2 Album-4
Artist-2 Album-5
Artist-3 Artist_Name Steely Dan
Artist-3 Song-8
Artist-3 Song-9
Artist-3 Song-10
Artist-3 Song-11
Artist-3 Album-6
Artist-3 Album-7
Song-1 Song_ArtistName-Released David Bowie_1972
Song-1 Song_Name Ziggy Stardust
Song-2 Song_ArtistName-Released David Bowie_1971
Song-2 Song_Name Changes
Song-3 Song_ArtistName-Released David Bowie_1977
Song-3 Song_Name Sons of the Silent Age
Song-4 Song_ArtistName-Released David Bowie_1977
Song-4 Song_Name Heroes
Song-5 Song_ArtistName-Released Bryan Adams_1988
Song-5 Song_Name Cloud Number Nine
Song-6 Song_ArtistName-Released Bryan Adams_1984
Song-6 Song_Name Summer of '69
Song-7 Song_ArtistName-Released Bryan Adams_1998
Song-7 Song_Name On a Day Like Today
Song-8 Song_ArtistName-Released Steely Dan_1972
Song-8 Song_Name Reelin' in the Years
Song-9 Song_ArtistName-Released Steely Dan_1972
Song-9 Song_Name Turn That Heartbeat Ov...
Song-10 Song_ArtistName-Released Steely Dan_1972
Song-10 Song_Name Change of the Guard
Song-11 Song_ArtistName-Released Steely Dan_1977
Song-11 Song_Name Deacon Blues
Album-1 Album_Genre Rock
Album-2 Album_Genre Rock
Album-3 Album_Genre Rock
Album-4 Album_Genre Alternative
Album-5 Album_Genre Rock
Album-6 Album_Genre Soft Rock
Album-7 Album_Genre Soft Rock

グローバルセカンダリインデックスGSI2をテーブルのSKをプライマリキー、テーブルのDataカラムをソートキーとして作ります。テーブルを見て分かる通り、Dataカラムはリレーションについては何も入っておらず、スパースなインデックスになっています。
例えば、GSI2のPK='Artist_Name'、SK='David Bowie'とすることで、David BowieのArtistID='Artist-1'を見つけられます。次に、テーブルのPK='Artist-1'、SK=begins_with('Song-')を指定すれば、David Bowieの曲のSong IDを取り出すことができます。
また、Song_ArtistName-Releasedという項目名をつくり、アーティスト名とリリース年の複合キーワードにも対応しています。

残りの項目

残りの項目は自分自身のエンティティIDをテーブルのSKに入れて、定義します。

PK(GSI1のSK) SK(GSI1のPK、GSI2のPK) Data(GSI2のSK) CareerStart Released Studio
Artist-1 Artist-1 1962
Artist-1 Artist_Name David Bowie
Artist-1 Song-1
Artist-1 Song-2
Artist-1 Song-3
Artist-1 Song-4
Artist-1 Album-1
Artist-1 Album-2
Artist-1 Album-3
Artist-2 Artist-2 1975
Artist-2 Artist_Name Bryan Adams
Artist-2 Song-5
Artist-2 Song-6
Artist-2 Song-7
Artist-2 Album-4
Artist-2 Album-5
Artist-3 Artist-3 1972
Artist-3 Artist_Name Steely Dan
Artist-3 Song-8
Artist-3 Song-9
Artist-3 Song-10
Artist-3 Song-11
Artist-3 Album-6
Artist-3 Album-7
Song-1 Song-1 1972
Song-1 Song_ArtistName-Released David Bowie_1972
Song-1 Song_Name Ziggy Stardust
Song-2 Song-2 1971
Song-2 Song_ArtistName-Released David Bowie_1971
Song-2 Song_Name Changes
Song-3 Song-3 1977
Song-3 Song_ArtistName-Released David Bowie_1977
Song-3 Song_Name Sons of the Silent Age
Song-4 Song-4 1977
Song-4 Song_ArtistName-Released David Bowie_1977
Song-4 Song_Name Heroes
Song-5 Song-5 1988
Song-5 Song_ArtistName-Released Bryan Adams_1988
Song-5 Song_Name Cloud Number Nine
Song-6 Song-6 1984
Song-6 Song_ArtistName-Released Bryan Adams_1984
Song-6 Song_Name Summer of '69
Song-7 Song-7 1998
Song-7 Song_ArtistName-Released Bryan Adams_1998
Song-7 Song_Name On a Day Like Today
Song-8 Song-8 1972
Song-8 Song_ArtistName-Released Steely Dan_1972
Song-8 Song_Name Reelin' in the Years
Song-9 Song-9 1972
Song-9 Song_ArtistName-Released Steely Dan_1972
Song-9 Song_Name Turn That Heartbeat Ov...
Song-10 Song-10 1972
Song-10 Song_ArtistName-Released Steely Dan_1972
Song-10 Song_Name Change of the Guard
Song-11 Song-11 1977
Song-11 Song_ArtistName-Released Steely Dan_1977
Song-11 Song_Name Deacon Blues
Album-1 Album-1 Trident Studios
Album-1 Album_Genre Rock
Album-2 Album-2 Trident Studios
Album-2 Album_Genre Rock
Album-3 Album-3 Hansa
Album-3 Album_Genre Rock
Album-4 Album-4 The Warehous...
Album-4 Album_Genre Alternative
Album-5 Album-5 Little Mountain...
Album-5 Album_Genre Rock
Album-6 Album-6 The Village Rec...
Album-6 Album_Genre Soft Rock
Album-7 Album-7 The Village Rec...
Album-7 Album_Genre Soft Rock

これで完成です。

テーブル1つにする設計の汎用的手法

これまでの例で見てきたことをまとめます。

  1. 隣接関係のリスト設計パターンを利用して、PKにエンティティID、SKに関連のあるエンティティIDを入れる
  2. テーブルのSKをPK、テーブルのPKをSKにしたグルーバルセカンダリインデックスをつくる
  3. クエリを洗い出す
  4. テーブルのSKにクエリ検索に使用する項目、テーブルのDataカラムにその項目の値を入れる
  5. テーブルのSKをPK、テーブルのDataカラムをSKとした多重定義なグルーバルセカンダリインデックスをつくる
  6. テーブルのPKと同じエンティティIDをSKに入れて、そのエンティティの属性を対応するカラムに入れる
  7. エンティティID、SKに入れる項目名は被らないようにルールを決める

クエリによってはこれだけで対応できず、グローバルセカンダリインデックスやローカルセカンダリインデックスが必要になることもあると思います。その時は臨機応変セカンダリインデックスを追加してください。また、項目の重複は恐れずに、クエリが効率化するようなスキーマになるように設計しましょう。

まとめ

  • DyanomoDBのテーブルはできるだけ少なく、理想は1つだけ
  • 必要なクエリを洗い出してから、テーブルのスキーマを決める
  • 隣接関係のリスト設計パターンとグルーバルセカンダリインデックスの多重定義を使ってテーブルのスキーマ設計を定型化できる
  • 項目の重複は恐れずに、クエリが効率化するようなスキーマにする

RDB技術者のためのNoSQLガイド

RDB技術者のためのNoSQLガイド