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