📃

DynamoDB、シングルテーブルかマルチテーブルか

に公開

DynamoDBを利用する際に、シングルテーブル設計とマルチテーブル設計のどちらを選ぶべきか判断するための参考記事があったので、その内容を整理しました。
https://aws.amazon.com/jp/blogs/news/single-table-vs-multi-table-design-in-amazon-dynamodb/

結論として、シングルテーブルの利点が重要でなければマルチテーブルでよいということでした。
それを理解するために前提となる仕組みと思想の話を少ししておきます。

DynamoDBのスケーラビリティを支える仕組み

  • パーティショニング:
    テーブルの各アイテムはPartition Keyをもち、データベースをパーティションごとに分けて保存します。
    適切なパーティションに素早くリクエストをルーティングすることによりクエリ時間を短縮します。

  • B-Tree:
    各パーティションのアイテムを、Sort Keyに従って整列されたB-Treeに格納します。B-Treeはソート順を維持したままデータを格納できるため、範囲指定クエリを効率的に処理できます。

背景にある思想=クエリの詳細を隠蔽しない

DynamoDBのテーブル定義にはPartition Key, Sort Keyを指定しますが、ここにはパーティショニングとB-Treeというクエリ効率化技術があからさまに表れています。
このような設計になっている背景にはデータベースの歴史の中でSQLが成し遂げたことの逆を行く思想があります。
SQLはクエリ実行の仕組みを抽象化し、ユーザーから隠蔽することで成功を収めました。ユーザーはどのようにデータを取得するかを意識せず、欲しい結果だけを記述すればよくなったのです。
一方で、データの大規模化やクエリ数の増加に伴うパフォーマンスの劣化やコストの増大を予測しづらいという問題を抱えるようになりました。
その問題を解消するため、DynamoDBはクエリの詳細を隠蔽しないAPIによりパフォーマンス・コストを予測しやすくしています。また、高レベルに抽象化された結合や集計といった操作も提供していません。
もちろんこれにもデメリットはあります。テーブル定義の時点で可能なクエリ方法がある程度決められてしまい、あらかじめ想定しないクエリに柔軟に対応するのが難しくなってしまいます。リレーショナルデータベースでもクエリパターンを想定してインデックスを貼るのは必要ですが、クエリ要件の追加・修正への柔軟な対応力に差が出てきます。

シングルテーブルかマルチテーブルか

以上の前提を踏まえてシングルテーブルとマルチテーブルどちらの設計をとるべきかの指針を考えていきます。

  • シングルテーブルが適する場合
    まとめてアクセスされる情報は1つのテーブルにまとめ、同一のPartition Keyに割り当てます。
    ただしまとめすぎには注意。アイテムが肥大化し、その一部だけ更新頻度が高い場合は、その部分を切り出して同一のPartition Keyに配置し、別のSort Keyを付与します。
    DynamoDBはテーブル単位で1つのインフラストラクチャなので、設定、監視、アラーム、バックアップといったオペレーション負荷を低減したい場合もシングルテーブルが適しています。

  • マルチテーブルが適する場合
    上記シングルテーブルの恩恵が重要でない場合、つまりアイテムの結合が必要なく、アイテムを複数の断片に分解しようともしておらず、運用負荷がシビアでもない場合、マルチテーブル設計の方が容易であればそれでよさそうです。
    より積極的にマルチテーブル設計を採用する理由としてDynamoDB Streamsに対して複数の要求がある場合と分析向けに使う場合があるようですが、興味があれば元記事を読んでください。

まとめ

目下の私の用途にはマルチテーブルが適しているようでした。
クエリパターンは決まっておりアイテム同士を結合する必要がないこと、アイテムに対する更新がないこと、テーブル数は片手で足りるほどであることからシングルテーブルである必要はありません。
データの種類によってその構造やクエリ方法が異なる可能性が高いので、むしろマルチテーブルが適しているといえそうです。

GitHubで編集を提案

Discussion