DynamoDBは高速でスケーラブルでとても便利なデータベースです。便利なのですが、テーブル設計にはRDBMSのノウハウをそのまま使えません。例えば、DynamoDBではテーブルを1つだけにすることが推奨されています。テーブルを1つだけにする設計手法について考えてみましょう。
DynamoDBの特長
DynamoDBはAWS(アマゾンウェブサービス)で提供される、とても便利なNoSQL データベースサービスです。高速なパフォーマンスとシームレスなスケーラビリティが特長です。
RDBMSではディスク容量が足りなくなったりしたら、基本的にはディスクを増やす等の「スケールアップ(リソースを一箇所に増やす)」をするという運用が発生します。この運用も頻繁にするのは面倒くさいので最初から大きめのディスク容量、CPU、メモリをとっておくことになります。
DynamoDBでは、データ量や読み書きの頻度に応じて自動的に「スケールアウト(リソースを複数箇所に増やしてアクセスを分散化)」してくれるのです。最初は最小限の費用から始められて、サービスが成長しても自動的に対応してくれるので、運用が非常に楽になります。
できるだけ少ないテーブル数で
DynamoDBの「開発者ガイド>ベストプラクティス>DynamoDB に合わせた NoSQL設計」を読んでいると衝撃の考え方が出てきます。
DynamoDB アプリケーションではできるだけ少ないテーブルを維持する必要があります。設計が優れたアプリケーションでは、必要なテーブルは 1 つのみです。
スケールアップはテーブル単位で行われます。テーブルを分割するとテーブル毎にデータ量やアクセス頻度が違うので、あるテーブルはスケールアウトされるがあるテーブルはスケールアウトされないままになったりします。キャパシティ管理が難しくなるのです、アプリケーション全体で容量やアクセス頻度を効率よく使うためには、テーブル数を少なくすることで、DynamoDBのリソースを効率良く使うことができるのです。
NoSQLデータベースはスキーマレスなので、どんなデータ構造でも入れることができ、つまりは1つのテーブルでどんなデータ構造でも対応できてしまうのです。
RDBMSで正規化を繰り返してテーブルを増やしていく設計思想とは真逆なのです。これははじめ何をどうしていいのか分かりませんでした。
1つのテーブルでの設計例
開発者ガイドにも「多対多の関係を管理するためのベストプラクティス」や「DynamoDB でリレーショナルデータをモデル化するためのベストプラクティス」があってテーブル1つでリレーショナル関係を設計する方法が書いてあるのですが、これだけ読んでもよくわからないです。
www.edx.org
この動画講座の「Week 4 > Schema Design > Single Table」を見ると1テーブルでの設計例があり、理解が深まりました。
データの収集
例えばArtist、Song、Albumの情報が以下のようにテーブル構造になっていたとします。
Artist | CarrerStart |
---|---|
David Bowie | 1962 |
Bryan Adams | 1975 |
Steely Dan | 1972 |
SongTitle | Artist | Released | AlbumTitle | Note |
---|---|---|---|---|
Ziggy Stardust | David Bowie | 1972 | The Rise and Fall of Zi... | This is a good so... |
Changes | David Bowie | 1971 | Hunky Dory | |
Sons of the Silent Age | David Bowie | 1977 | Heroes | |
Heroes | David Bowie | 1977 | Heroes | Good |
Cloud Number Nine | Bryan Adams | 1988 | On a Day Like Today | |
Summer of '69 | Bryan Adams | 1984 | Reckless | |
On a Day Like Today | Bryan Adams | 1998 | On a Day Like Today | |
Reelin' in the Years | Steely Dan | 1972 | Can't Buy a Thrill | |
Turn That Heartbeat Ov... | Steely Dan | 1972 | Can't Buy a Thrill | |
Change of the Guard | Steely Dan | 1972 | Can't Buy a Thrill | |
Deacon Blues | Steely Dan | 1977 | Aja |
AlubumTitle | ArtistName | Genre | Studio |
---|---|---|---|
The Rise and Fall of Zi... | David Bowie | Rock | Trident Studios |
Hunky Dory | David Bowie | Rock | Trident Studios |
Heros | David Bowie | Rock | Hansa |
On a Day Like Today | Bryan Adams | Alternative | The Warehous... |
Reckless | Bryan Adams | Rock | Little Mountain... |
Can't Buy a Thrill | Steely Dan | Soft Rock | The Village Rec... |
Aja | Steely Dan | Soft Rock | The Village Rec... |
クエリの洗い出し
RBMSではデータ構造を考えるときに正規化を粛々と進めていくのですが、NoSQLではアプリケーションに使うクエリを考えます。
例えば以下のようなクエリーがアプリケーションに必要だとします。
- アーティスト名を指定してすべての曲を見つける
- ジャンルを指定してすべてのアルバムを見つける
- リリース年とアーティスト名から曲を検索する
- 曲名から同じ曲名の曲を検索する
1つのテーブルにする
NoSQLはスキーマレスなので1つのテーブルにするのは簡単ですが、注意しなくてはいけないのはPartition KeyとSort Keyを何にするかです。
まずAristテーブルから考えましょう。アーティスト名をキーにできればいいので、ArtistNameをPartition Keyにします。ここでコツがあって、Sort KeyにもArtistNameを入れておきます。
Partition Key | Sort Key | CareerStart | Released | Genre | Album | Studio |
---|---|---|---|---|---|---|
David Bowie | David Bowie | 1962 | ||||
Bryan Adams | Bryan Adams | 1975 | ||||
Steely Dan | Steely Dan | 1972 |
次にSongテーブルを考えます。ArtistNameをPartition Keyにしたので、Sort KeyにSongTitleを入れましょう。
Partition Key | Sort Key | CareerStart | Released | Genre | Album | Studio |
---|---|---|---|---|---|---|
David Bowie | David Bowie | 1962 | ||||
David Bowie | Ziggy Stardust | 1972 | The Rise and Fall of Zi... | |||
David Bowie | Changes | 1971 | Hunky Dory | |||
David Bowie | Sons of the Silent Age | 1977 | Heroes | |||
David Bowie | Heroes | 1977 | Heroes | |||
Bryan Adams | Bryan Adams | 1975 | ||||
Bryan Adams | Cloud Number Nine | 1988 | On a Day Like Today | |||
Bryan Adams | Summer of '69 | 1984 | Reckless | |||
Bryan Adams | On a Day Like Today | 1988 | On a Day Like Today | |||
Steely Dan | Steely Dan | 1972 | ||||
Steely Dan | Reelin' in the Years | 1972 | Can't Buy a Threill | |||
Steely Dan | Turn That Heartbeat Ov... | 1972 | Can't Buy a Threill | |||
Steely Dan | Change of the Guard | 1972 | Can't Buy a Threill | |||
Steely Dan | Deacon Blues | 1977 | Aja |
最後にAlbumテーブルの情報を入れます。ArtistNameをPartition Keyにしたので、Sort KeyにAlbumTitleを入れましょう。
Partition Key | Sort Key | CareerStart | Released | Genre | Album | Studio |
---|---|---|---|---|---|---|
David Bowie | David Bowie | 1962 | ||||
David Bowie | Ziggy Stardust | 1972 | The Rise and Fall of Zi... | |||
David Bowie | Changes | 1971 | Hunky Dory | |||
David Bowie | Sons of the Silent Age | 1977 | Heroes | |||
David Bowie | Heroes | 1977 | Heroes | |||
David Bowie | The Rise and Fall of Zi... | Rock | Trident Studios | |||
David Bowie | Hunky Dory | Rock | Trident Studios | |||
David Bowie | Heros | Rock | Hansa | |||
Bryan Adams | Bryan Adams | 1975 | ||||
Bryan Adams | Cloud Number Nine | 1988 | On a Day Like Today | |||
Bryan Adams | Summer of '69 | 1984 | Reckless | |||
Bryan Adams | On a Day Like Today | 1988 | On a Day Like Today | |||
Bryan Adams | On a Day Like Today | Alternative | The Warehous... | |||
Bryan Adams | Reckless | Rock | Little Mountain... | |||
Steely Dan | Steely Dan | 1972 | ||||
Steely Dan | Reelin' in the Years | 1972 | Can't Buy a Thrill | |||
Steely Dan | Turn That Heartbeat Ov... | 1972 | Can't Buy a Threill | |||
Steely Dan | Change of the Guard | 1972 | Can't Buy a Thrill | |||
Steely Dan | Deacon Blues | 1977 | Aja | |||
Steely Dan | Can't Buy a Thrill | Soft Rock | The Village Rec... | |||
Steely Dan | Aja | Soft Rock | The Village Rec... |
これでテーブルはできあがりです。正規化とは対立する手法ですね。
クエリーにあわせてセカンダリーインデックス
「アーティスト名を指定してすべての曲を見つける」
これは簡単です。
Prtition KeyにAristNameが入っているので、Releasedが入っているレコードを見つけてくればいいだけです。
「ジャンルを指定してすべてのアルバムを見つける」
GenreをPatrition Keyとしたグローバルセカンダリインデックスを作ります。Genreカラムが入っているレコードのSort Keyがアルバムになります
「リリース年とアーティスト名から曲を検索する」
アーティスト名はPartition Keyに使われていますので、ReleasedをSort Keyとしたローカルセカンダリインデックスを作ればいけます。Partition Keyはすでにあるのでローカルセカンダリインデックスはなくてもいいのですが、曲名以外にはRelease属性はついていないためインデックスの容量が少なくてすみ、検索がとても効率的に働きます。こういうインデックスをスパースなインデックスといい、DynamoDBで推奨されています。
「曲名から同じ曲名の曲を検索する」
曲名(=Sort Key)をPatrition Keyとしたグローバルセカンダリインデックスを作ります。Releasedが入っているレコードを見つけてくればいいでしょう。
最終的に1つのテーブル、2つのグルーバルセカンダリインデックス、1つのローカルセカンダリインデックスをつくれば、クエリー要件は満たすことができます。
設計を汎用的に
上述の例を考えると、Partition Keyに一番重要そうなテーブルのプライマリキー、Sort Keyにそのテーブルとリレーショナルなテーブルのプライマリキーを入れることで実現できます。Partition KeyとSort Keyだけを見るとテーブルの関係性を示しています。この設計手法を隣接関係のリスト設計パターンと言います。
実際このやり方で1つのテーブルに収めればいいのですが、Partition Keyにはクエリーで使用する文字列でなくユニークなIDを入れたくなるケースがあります。
例えば、アーティス名はユニークであるとは限りません。アーティスト名で検索してアーティストIDを見つけて、それからアーティストIDで曲名を検索するようなステップが必要です。その場合、アーティストIDをPartition Keyにしたテーブルを作成し、アーティスト名をPartition Keyにしたグローバルセカンダリインデックスをつくることになります。このあたりを考慮した、もう少し汎用的な設計手法を次の投稿で書きたいと思います。
まとめ
- DynamoDBは高速でスケーラブルはNoSQLデータベース
- テーブルはできるだけ少なく、理想は1つだけ
- 必要なクエリを洗い出してから、テーブルの構造を決める
- Partition Keyに一番重要そうなテーブルのプライマリキー、Sort Keyにリレーショナルなテーブルのプライマリキーを入れるのがコツ(隣接関係のリスト設計パターン)
- クエリが効率的に働くようなセカンダリインデックスをつける
サーバーレスシングルページアプリケーション ―S3、AWS Lambda、API Gateway、DynamoDB、Cognitoで構築するスケーラブルなWebサービス
- 作者: Ben Rady,吉田真吾,笹井崇司
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/06/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (2件) を見る
- 作者: 渡部徹太郎,河村康爾,北沢匠,佐伯嘉康,佐藤直生,原沢滋,平山毅,李昌桓
- 出版社/メーカー: 秀和システム
- 発売日: 2016/02/24
- メディア: 単行本
- この商品を含むブログ (3件) を見る