💻
DynamoDBマスターガイド 〜俺でも分かるAWSのNoSQL〜
0. このカンニングペーパーの使い方
このカンニングペーパーではDynamoDBの基本から実践的な使い方まで、コンパクトにまとめています。困った時に参照してください。専門用語には太字で印をつけてあります。
1. DynamoDBの基本:そもそも何者?
1.1 DynamoDBとは?
- AWSが提供するNoSQLデータベース
- 従来のRDB(MySQL, PostgreSQLなど)と違い、テーブル間の関連性より「速さ」と「スケーラビリティ」を重視
- フルマネージド型(運用の手間が少ない)
- ミリ秒単位の応答速度が特徴
1.2 RDBとの主な違い
項目 | RDB (例:RDS) | DynamoDB |
---|---|---|
データモデル | 正規化されたテーブル、固定スキーマ | スキーマレス、柔軟な構造 |
クエリ言語 | SQL | 専用API (SQLなし) |
スケーリング | 垂直スケーリング(サーバースペックアップ) | 水平スケーリング(分散自動化) |
設計アプローチ | スキーマ先行設計 | アクセスパターン先行設計 |
得意分野 | 複雑なJOIN、複雑なクエリ | シンプルな読み書きの高速処理 |
1.3 基本的な構造
- テーブル:データの箱。例えば「ユーザーテーブル」「商品テーブル」。
- アイテム:テーブル内の1レコード。例えば「ユーザーテーブル内の田中さんのデータ」。
- 属性:アイテムが持つ情報。例えば「名前」「年齢」「メールアドレス」。
// ユーザーテーブルのアイテム例
{
"user_id": "123",
"name": "田中太郎",
"email": "tanaka@example.com",
"age": 28,
"preferences": {
"theme": "dark",
"notifications": true
},
"last_login": "2025-03-20T10:30:00Z"
}
2. キホンのキ:キーの理解
2.1 キーの種類
-
プライマリキー:必須。以下の2種類がある
- パーティションキーのみ:単一キー構成
- パーティションキー + ソートキー:複合キー構成
2.2 パーティションキーとは?
- データがどの区画(パーティション)に保存されるかを決める値
- 例えば「user_id」「product_id」など
- 均等に分散する値を選ぶとパフォーマンスが向上
- 👉 ホットパーティション問題:特定のパーティションにアクセスが集中すると性能低下
2.3 ソートキーとは?
- 同じパーティション内でのデータの並び順を決める値
- 例えば「登録日」「注文ID」など
- 範囲検索(○○以上××以下)も可能
- パーティションキーとセットで一意になるように設計
パーティションキー:user_id = "123"
ソートキー:timestamp = "2025-03-01T..." 〜 "2025-03-31T..."
→ 3月の全注文履歴が取得できる
3. データの取り出し方
3.1 クエリ操作
- 特定のパーティションキーに対してデータを取得
- 効率が良く、高速
- ソートキーがある場合は、その範囲や条件での絞り込みも可能
// JavaScriptでの例
const params = {
TableName: "Users",
KeyConditionExpression: "user_id = :uid",
ExpressionAttributeValues: {
":uid": "123"
}
};
await dynamodb.query(params).promise();
3.2 スキャン操作
- テーブル全体を一つずつ確認する方法
- データが多いとめっちゃ時間かかるしコストもかかる
- できるだけ避けるべき操作
// JavaScriptでの例 (非推奨)
const params = {
TableName: "Users",
FilterExpression: "age > :min_age",
ExpressionAttributeValues: {
":min_age": 20
}
};
await dynamodb.scan(params).promise();
4. インデックスで検索を効率化
4.1 グローバルセカンダリインデックス (GSI)
- パーティションキーとは別の属性でデータを探せるようにする
- 例:ユーザーIDではなく、メールアドレスからユーザーを探したい
- テーブル作成後でも追加・変更・削除可能
// メールアドレスからユーザーを検索する例
const params = {
TableName: "Users",
IndexName: "email-index",
KeyConditionExpression: "email = :email",
ExpressionAttributeValues: {
":email": "tanaka@example.com"
}
};
await dynamodb.query(params).promise();
4.2 ローカルセカンダリインデックス (LSI)
- 同じパーティションキーだけど、別のソートキーでデータを探せるようにする
- テーブル作成時にしか設定できない
- 使用頻度はGSIより少ない
5. キャパシティ設定:DynamoDBの処理能力
5.1 プロビジョンドモード
- 1秒間に何回読み書きできるかを事前に設定
- RCU(読み取りキャパシティユニット)とWCU(書き込みキャパシティユニット)で設定
- 予測可能なトラフィックに最適
- 自動スケーリングと組み合わせて使うのが一般的
5.2 オンデマンドモード
- 使った分だけ支払う方式
- 急なアクセス増加にも自動対応
- トラフィック予測が難しい場合に便利
- ただし、長期的にはプロビジョンドより高くなりがち
5.3 💰 コスト比較ヒント
- スタートアップフェーズ → オンデマンド(柔軟性重視)
- 安定フェーズ → プロビジョンド + 自動スケーリング(コスト最適化)
- 一時的な大量アクセスがある場合 → イベント前にプロビジョンドの容量増強
6. 便利な追加機能
6.1 TTL(Time To Live)- データの賞味期限設定
- データに有効期限をつけて自動削除
- セッション情報や一時データに最適
- バックアップコストの削減にも効果的
// TTLの例:24時間後に削除される一時トークン
{
"token_id": "abc123",
"token_value": "xyz789",
"user_id": "123",
"expiration": 1711392000 // Unix時間
}
6.2 DAX(DynamoDB Accelerator)
- インメモリキャッシュでめっちゃ高速化(マイクロ秒単位)
- 読み取りの多いワークロードに有効
- 実装は簡単(SDK差し替えるだけ)
6.3 トランザクション
- 複数の操作を一括で実行(全部成功か全部失敗か)
- 例:在庫減らす+注文確定など
- RDBMSのACID特性に近い安全性
6.4 ストリーム
- テーブルの変更をリアルタイムで捕捉
- Lambda関数との連携で様々な自動処理が可能
- 例:注文テーブル更新→自動メール送信
6.5 グローバルテーブル
- 世界中の複数リージョンにデータを自動複製
- 低レイテンシーのグローバルアプリに最適
- マルチリージョン障害対策にも
7. DynamoDBの設計アプローチ(超重要)
7.1 RDBとDynamoDBの設計思想の違い
- RDB→「データをどう保存するか」から考える
- DynamoDB→「データをどう取り出すか」から考える
7.2 設計ステップ
- アクセスパターンを洗い出す(どんなクエリが必要か全部リストアップ)
- キー構造を設計(パーティションキー、ソートキー)
- 必要なインデックスを計画(GSI、LSI)
- 非正規化を検討(JOIN操作がないので、データを複製することも)
7.3 よくある設計パターン
シングルテーブルデザイン
- 複数のエンティティを1つのテーブルに格納
- PKとSKの組み合わせでエンティティを区別
- 一見複雑だが、パフォーマンスが高く、JOINが不要に
// ユーザーアイテム
{
"PK": "USER#123",
"SK": "PROFILE",
"name": "田中太郎",
"email": "tanaka@example.com"
}
// 同じユーザーの注文アイテム
{
"PK": "USER#123",
"SK": "ORDER#456",
"orderDate": "2025-03-24",
"amount": 5000
}
GSIオーバーロード
- 1つのGSIを複数の用途で利用
- データ属性を使い分けることで様々なクエリを実現
// GSI1-PK と GSI1-SK を複数の用途で使い回す
// 例: 商品検索用
{
"PK": "PRODUCT#789",
"SK": "METADATA",
"name": "ゲーミングPC",
"GSI1-PK": "CATEGORY#electronics",
"GSI1-SK": "PRODUCT#ゲーミングPC"
}
// 例: メール検索用
{
"PK": "USER#123",
"SK": "PROFILE",
"name": "田中太郎",
"email": "tanaka@example.com",
"GSI1-PK": "EMAIL#tanaka@example.com",
"GSI1-SK": "USER#123"
}
8. DynamoDB vs RDS 選択ガイド
8.1 DynamoDBが最適なケース
- 高いスケーラビリティが必要
- シンプルなキーバリュー検索が中心
- 低レイテンシーが絶対条件
- サーバーレスアーキテクチャとの連携
8.2 RDSが最適なケース
- 複雑なJOINクエリが必要
- トランザクション整合性が重要
- 複雑な分析や集計が必要
- SQLの専門知識を持つチームがある
8.3 実ユースケース例
DynamoDBが向いている例
- セッション管理(高速アクセス)
- ユーザープロファイル
- ゲームのスコアボード
- IoTデータの収集
- リアルタイムダッシュボード
RDSが向いている例
- 財務システム
- 複雑な検索が必要なECサイト
- BI/分析システム
- 複雑なレポート生成システム
9. コスト最適化のコツ
9.1 DynamoDBのコスト要素
- 読み取り/書き込みキャパシティ
- ストレージ量
- データ転送量
- バックアップと追加機能
9.2 コスト削減テクニック
- 適切なキャパシティモードの選択
- 自動スケーリングの設定(プロビジョンドの場合)
- 不要なGSIの削除(GSIもコストがかかる)
- TTLで不要データを自動削除
- 大量読み取りにはDAXの検討
10. よくあるトラブルと対策
10.1 ホットパーティション問題
- 特定のパーティションに負荷が集中する問題
- 対策:パーティションキーの再設計、ハッシュ接尾辞の追加など
// 不均一なアクセスを分散させる例
// user_id + 乱数 でパーティションキーを作成
const randomSuffix = Math.floor(Math.random() * 10);
const partitionKey = `${userId}_${randomSuffix}`;
10.2 スロットリング(リクエスト制限)
- キャパシティを超過するとリクエストが拒否される
- 対策:指数バックオフ&リトライ、キャパシティ増強
10.3 スキャン操作の非効率性
- 全テーブルスキャンは避ける
- 対策:パラレルスキャン、ページネーション、GSIの活用
11. DynamoDBを使うときの実践的なTips
11.1 開発環境のセットアップ
- ローカル開発には「DynamoDB Local」を使える
- AWS CLIとDynamoDB管理ツール(NoSQL Workbench)の活用
11.2 データのバックアップ
- オンデマンドバックアップの活用
- Point-in-Time Recovery(PITR)の設定
11.3 コーディングのベストプラクティス
- バッチ操作の活用(BatchGetItem, BatchWriteItem)
- 条件付き書き込みで楽観的ロックを実装
- SDKのページネーション機能を活用
12. まとめ:これだけ覚えておけばOK
- DynamoDBはスケーラビリティとパフォーマンスに優れたNoSQLデータベース
- 「どうデータを取り出すか」から設計を始める
- パーティションキーの選定がパフォーマンスの鍵
- JOINがないので、アクセスパターンに合わせた非正規化が必要
- GSIを効果的に活用して複数の検索パターンを実現
- コスト管理は、使用パターンに合わせたモード選択と定期的な見直しが重要
これでDynamoDBの基本から実践的な活用方法まで、コンパクトに理解できるようになりました。どんどん実際に使ってみて、経験を積んでいくことをオススメします!
Discussion