SQLユーザーがDynamoDBを使うと嵌まるポイント
概要¶
SQL に慣れたエンジニアが DynamoDB を使い始めると「SQL と同じ感覚で使うとハマる」ポイントが多い。DevelopersIO の記事を紹介する形で話題になった投稿。
詳細¶
SQL との根本的な違い¶
SQL(RDB):
→ スキーマを先に決める
→ JOIN で柔軟にデータを取得
→ WHERE 句で任意のカラムを条件にできる
→ テーブルスキャンは遅いがとりあえず動く
DynamoDB(NoSQL):
→ スキーマレス(カラムは後から追加可能)
→ JOIN は存在しない(アプリケーション側で結合)
→ PK/SK 以外の条件でのクエリは GSI が必要
→ フルスキャンは超高額 + 遅い(使ってはいけない)
嵌まりやすいポイント¶
1. PK 設計を後から変えられない¶
テーブル作成後に PK(Partition Key)を変えることはできない。
アクセスパターンを先にリストアップして PK を設計することが必須。
悪い設計: users テーブルに pk = user_id だけ
→ 「会社に所属するユーザー一覧を取得」しようとすると全スキャン
良い設計: GSI を追加して company_id でも検索できるようにする
2. フルスキャンは避ける¶
// 絶対にやってはいけない(小規模なら動くが本番ではコスト爆発)
result, err := client.Scan(ctx, &dynamodb.ScanInput{
TableName: aws.String("users"),
})
// 正しい: Query で PK または GSI を使う
result, err := client.Query(ctx, &dynamodb.QueryInput{
TableName: aws.String("users"),
KeyConditionExpression: aws.String("pk = :pk"),
ExpressionAttributeValues: map[string]types.AttributeValue{
":pk": &types.AttributeValueMemberS{Value: "USER#" + userID},
},
})
3. 1リクエスト 1MB 制限¶
Query/Scan の1回のレスポンスは最大 1MB。
1MB を超えると LastEvaluatedKey が返る → ページネーションが必要。
for {
result, _ := client.Query(ctx, input)
// 処理...
if result.LastEvaluatedKey == nil { break }
input.ExclusiveStartKey = result.LastEvaluatedKey
}
4. トランザクションは2テーブル・25アイテムまで¶
DynamoDB トランザクションは TransactWriteItems で最大 25 アイテムまで。複雑なトランザクションは RDB の方が向いている。
DynamoDB が向いているケース¶
✓ キー・バリューの単純な読み書き(超高スループット)
✓ セッション管理(TTL で自動削除)
✓ リアルタイムゲームのスコアボード
✓ IoT デバイスのセンサーデータ
✗ 複雑な JOIN が必要なデータ
✗ アクセスパターンが不明確
✗ 集計クエリが多い
なぜ重要か / いつ使うか¶
- AWS で NoSQL を選定するとき
- 既存 RDB を DynamoDB に移行することを検討するとき
- DynamoDB の設計レビューで「スキャンしていないか」を確認するとき