非正規化

読み取り性能を向上させるために、意図的にデータの冗長性を持たせる設計手法

データベース設計

非正規化とは

非正規化 (Denormalization) は、正規化されたデータベースに意図的に冗長性を持たせ、読み取り性能を向上させる設計手法である。JOIN を排除し、1 回のクエリで必要なデータを取得できるようにする。

正規化 vs 非正規化

正規化と非正規化の違いを以下にまとめる。

観点正規化非正規化
冗長性なしあり (意図的)
読み取り遅い (JOIN が必要)速い (1 回のクエリ)
書き込み速い (1 箇所を更新)遅い (複数箇所を更新)
一貫性高い低い (同期が必要)
ストレージ効率的冗長

DynamoDB での非正規化

DynamoDB は JOIN をサポートしないため、非正規化が基本設計となる。

// ❌ 正規化 (RDS 的な設計): 2 回のクエリが必要
// orders テーブル: { orderId: "1", userId: "U1" }
// users テーブル:  { userId: "U1", name: "Alice" }

// ✅ 非正規化: 1 回のクエリで取得
{
  "orderId": "1",
  "userId": "U1",
  "userName": "Alice",
  "items": [
    { "product": "りんご", "price": 100 }
  ]
}

非正規化のパターン

非正規化のパターンを以下にまとめる。

パターン説明
埋め込み関連データをアイテム内に埋め込む注文に顧客名を含める
複製同じデータを複数のアイテムに持つ商品名を注文明細にも持つ
集計値の事前計算集計結果を保存注文の合計金額を保存

一貫性の維持

非正規化したデータの一貫性を維持する方法:

// DynamoDB トランザクションで複数アイテムを同時更新
await db.transactWrite({
  TransactItems: [
    { Update: { TableName: 'orders', Key: { id: orderId }, UpdateExpression: 'SET userName = :name', ... } },
    { Update: { TableName: 'users', Key: { id: userId }, UpdateExpression: 'SET #name = :name', ... } },
  ],
});
// DynamoDB Streams で非同期に同期
[users テーブル更新][DynamoDB Streams][Lambda][orders テーブルの userName を更新]

いつ非正規化するか

いつ非正規化するかの判断基準を以下にまとめる。

ケース推奨
DynamoDB (NoSQL)✅ 基本的に非正規化
読み取りが圧倒的に多い✅ 非正規化
書き込みが多く一貫性が重要❌ 正規化 (RDS)
データの更新頻度が低い✅ 非正規化 (同期コストが低い)

非正規化の背景や設計思想は関連書籍に詳しい。

この記事は役に立ちましたか?

関連用語

関連する記事