1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RDS経験者のためのDynamoDBデータモデリング入門

1
Posted at

この記事は何?

開発でDynamoDBを使用する機会があり、設計の注意点について調べた内容のメモ。

誰向けの記事?

RDS(MySQL, Postgresなど)の経験はあるが、DynamoDBは初めて/初心者の人

はじめに: DynamoDBは「先にアクセスパターンを決めてからスキーマを設計する」データベース

RDSではまずデータを正規化し、あとからSQLで柔軟にクエリを組み立てる。DynamoDBでは逆に、アプリケーションが必要とするクエリを先に洗い出し、そのクエリに最適化した形でデータを格納する。この発想の転換が最も重要であり、RDS経験者が最もつまずきやすいポイントでもある。

背景

RDSでは正規化によりデータ重複を排除し、JOINで柔軟にデータを再構成できる。
しかしDynamoDBにはJOINがなく、クエリの柔軟性が限定されている。RDSの設計手法をそのまま持ち込むと、パフォーマンスやコストの問題に直面する。

DynamoDBの基本概念 — RDSとの用語対応

RDSに慣れている人がまず押さえるべき、DynamoDB固有の概念を整理する。

RDSとの用語マッピング

RDS(RDBMS) DynamoDB 備考
テーブル テーブル 同じ
行(row) アイテム(item) 1件のレコードに相当
列(column) 属性(attribute) ただしスキーマレス。アイテムごとに属性が異なってよい
主キー パーティションキー(+ ソートキー) 後述
セカンダリインデックス GSI / LSI 後述
SQL Query / Scan / GetItem / PutItem 等のAPI SQLは使えない(PartiQLという簡易SQLもあるが基本はAPI)

テーブル・アイテム・属性

DynamoDBのテーブルはアイテム(RDSでいう行)の集合で、各アイテムは属性(RDSでいう列)の集合。RDSと異なり、主キー以外の属性は事前定義不要で、アイテムごとに異なる属性を持てる。

// PersonIDだけが必須(主キー)。他の属性はアイテムごとに自由
{ "PersonID": 101, "Name": "田中", "Phone": "090-xxxx" }
{ "PersonID": 102, "Name": "佐藤", "Address": {"City": "東京"}, "FavoriteColor": "Blue" }

プライマリキー:パーティションキーとソートキー

DynamoDBのプライマリキーは2種類ある。

1. パーティションキーのみ(単純主キー)
RDSの単一カラム主キーに近い。パーティションキーの値でアイテムの物理的な格納先(パーティション)が決まる。

2. パーティションキー+ソートキー(複合主キー)
RDSの複合主キーに近いが、役割が異なる。同じパーティションキーを持つアイテムは物理的に近くに格納され、ソートキーの昇順で並ぶ。この「同じパーティションキーを持つアイテムの集合」をアイテムコレクションと呼ぶ。

// Musicテーブル: Artist(PK) + SongTitle(SK)
{ "Artist": "YUI", "SongTitle": "CHE.R.RY", "Album": "..." }
{ "Artist": "YUI", "SongTitle": "TOKYO",    "Album": "..." }  // 同じPKなので近くに格納
{ "Artist": "aiko", "SongTitle": "花火",     "Album": "..." }  // 別パーティション

この構造により、Artist = "YUI" でQueryすれば、YUIの全曲がソートキー順で効率的に取得できる。RDSの SELECT * FROM Music WHERE Artist = 'YUI' ORDER BY SongTitle に相当するが、JOINなしで高速に動作する。

セカンダリインデックス(GSI / LSI)

テーブルの主キー以外の切り口でデータを検索したい場合に使う。RDSの CREATE INDEX に相当するが、仕組みが異なる。

  • GSI(グローバルセカンダリインデックス): テーブルとは異なるパーティションキー・ソートキーを指定できる。実体としてはデータのコピーが別途管理される(RDSのマテリアライズドビューに近い感覚)。テーブルあたり最大20個。
  • LSI(ローカルセカンダリインデックス): パーティションキーはテーブルと同じで、ソートキーだけ変える。テーブル作成時にしか定義できない。テーブルあたり最大5個。

データの読み書きオペレーション

操作 RDS相当 説明
GetItem SELECT ... WHERE pk = ? 主キー指定で1件取得
Query SELECT ... WHERE pk = ? AND sk BETWEEN ... パーティションキー指定+ソートキー条件で複数件取得
Scan SELECT * FROM table 全件走査。高コストなので基本的に避ける
PutItem INSERT / REPLACE 1件書き込み(存在すれば上書き)
UpdateItem UPDATE ... WHERE pk = ? 属性単位で部分更新
DeleteItem DELETE ... WHERE pk = ? 1件削除
BatchGetItem 複数SELECT 最大100件を一括取得
TransactWriteItems BEGIN; ... COMMIT; 最大100項目のACIDトランザクション

キャパシティモード

RDSはインスタンスサイズで性能が決まるが、DynamoDBはテーブル単位でスループットを制御する。

  • オンデマンドモード: リクエストに応じて自動スケール。予測しにくいワークロード向け
  • プロビジョンドモード: 読み取り/書き込みキャパシティユニット(RCU/WCU)を事前に指定。Auto Scalingと組み合わせ可能

参考: Core components of Amazon DynamoDB / Partitions and data distribution


スキーマ設計の進め方が根本的に異なる

RDS DynamoDB
設計の起点 データの構造(ER図) アクセスパターン(どんなクエリが必要か)
正規化 推奨(3NF等) 非推奨。積極的にデノーマライズする
テーブル数 エンティティごとにテーブルを作る できるだけ少なく。シングルテーブル設計が基本
スキーマ変更 ALTER TABLEで列追加 スキーマレス。項目ごとに属性が異なってよい

NoSQL design for DynamoDB

JOINの代わりにデータの持ち方で解決する

RDSでは正規化してJOINで組み立てるが、DynamoDBではJOINがないため、1回のクエリで必要なデータが全て取れるようにデータを配置する。

RDSの手法 DynamoDBでの代替
JOINで複数テーブルを結合 関連データを同じパーティションキーの下にまとめる(アイテムコレクション)
外部キーによるリレーション 複合キー(パーティションキー+ソートキー)で1対多を表現
多対多の中間テーブル 隣接リストパターン(adjacency list)+GSI(逆引きインデックス)
VIEWや集約クエリ GSI(グローバルセカンダリインデックス)で別の切り口のクエリを実現

Best practices for modeling relational data

キー設計がパフォーマンスの全てを決める

RDSでは主キーは一意性の保証が主目的で、パフォーマンスはインデックスやクエリオプティマイザが担う。DynamoDBではキー設計がデータの物理配置とクエリ性能を直接決定する。

  • パーティションキー: カーディナリティの高い属性を選ぶ。偏ると特定パーティションにホットスポットが発生する(RDSのAUTO_INCREMENTのような連番IDは不向き)
  • ソートキー: 範囲検索(begins_with, between)に使える。階層構造を複合ソートキー(例: COUNTRY#JP#CITY#TOKYO)で表現する
  • GSI(グローバルセカンダリインデックス): RDSのセカンダリインデックスに近いが、別テーブルのように独自のキースキーマを持つ。追加のクエリパターンに対応する手段

Data modeling for DynamoDB

RDS経験者が特に注意すべき点

  • 「あとからクエリを追加」が難しい: RDSならSQLを書けば済むが、DynamoDBでは新しいアクセスパターンにはGSI追加やデータ構造の変更が必要になることがある
  • Scanは避ける: RDSのSELECT * FROM tableに相当するScanは全件読み取りで高コスト。Queryで取れる設計にする
  • トランザクションは限定的: DynamoDBにもTransactWriteItems/TransactGetItemsがあるが、1回のトランザクションで操作できるのは100項目まで。RDSのような長時間トランザクションは不可
  • アイテムサイズ上限は400KB: 大きなデータはS3に置いて参照を保持するパターンが推奨
  • テーブル数の上限はアカウントあたり10,000: RDSのように無制限にテーブルを作る設計は合わない

参考ドキュメント

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?