LESSON 25分

ストーリー

「新しいプロジェクトのデータベースはMongoDBでいきましょう!」

チームメンバーの提案に、高橋アーキテクトが落ち着いて問いかける。

「なぜMongoDBなんだ? 技術選定は『使いたいから』ではなく『要件に合っているから』で判断する。RDBとNoSQL、それぞれの強みと限界を正しく理解した上で選ぶんだ」


判断フレームワーク

Step 1: データの特性を分析する

質問RDB寄りNoSQL寄り
データ構造は固定か?固定・変更少ない柔軟・頻繁に変わる
関連(リレーション)は複雑か?複雑なJOINが必要シンプルな関連
トランザクションの要件は?ACID必須結果整合性で十分
データ量は?数百万~数億行数十億行以上
スケール要件は?垂直スケールで十分水平スケール必須

Step 2: アクセスパターンを分析する

質問RDB寄りNoSQL寄り
読み書きの比率は?読み書き均等読み重 or 書き重に偏る
クエリパターンは?多様・アドホック固定的・予測可能
レイテンシ要件は?数十ms許容サブミリ秒が必要
同時接続数は?数百~数千数万~数十万

比較表

特性RDBNoSQL
スキーマ固定(schema-on-write)柔軟(schema-on-read)
整合性強い整合性(ACID)結果整合性(BASE)
スケーリング垂直(スケールアップ)水平(スケールアウト)
JOINネイティブサポート限定的 or なし
トランザクション完全サポート限定的サポート
クエリ言語SQL(標準化)製品固有のAPI
成熟度50年以上の歴史比較的新しい

ユースケース別の推奨

RDBが適しているケース

1. 金融・決済システム
   → ACID トランザクションが必須
   → 複雑なリレーションと整合性制約

2. ERPシステム
   → 構造化された定型データ
   → 複雑なレポート・集計クエリ

3. ユーザー管理・認証
   → 一意性制約(email, username)
   → 外部キーによる参照整合性
// RDB向き: 送金処理(ACID必須)
async function transferFunds(
  fromAccountId: number,
  toAccountId: number,
  amount: number
): Promise<void> {
  await prisma.$transaction(async (tx) => {
    // 送金元の残高を減らす
    const from = await tx.account.update({
      where: { id: fromAccountId },
      data: { balance: { decrement: amount } },
    });

    if (from.balance < 0) {
      throw new Error('Insufficient funds');
    }

    // 送金先の残高を増やす
    await tx.account.update({
      where: { id: toAccountId },
      data: { balance: { increment: amount } },
    });
  });
}

NoSQLが適しているケース

1. SNSのタイムライン
   → 大量の書き込みと読み込み
   → 柔軟なコンテンツ構造(テキスト、画像、動画)

2. IoTデータ
   → 大量の時系列データの書き込み
   → 水平スケールが必須

3. リアルタイムゲーム
   → サブミリ秒のレスポンス要件
   → セッション状態の高速管理

4. コンテンツ管理(CMS)
   → 各記事が異なる構造を持つ
   → スキーマの柔軟性が必要
// NoSQL向き: CMSのコンテンツ管理(MongoDB)
// 記事の種類によって構造が異なる
const blogPost = {
  _id: new ObjectId(),
  type: 'blog',
  title: 'MongoDBの使い方',
  body: '...',
  tags: ['mongodb', 'database'],
  author: { name: '田中', avatar: '/img/tanaka.jpg' },
};

const photoGallery = {
  _id: new ObjectId(),
  type: 'gallery',
  title: '春の写真集',
  photos: [
    { url: '/img/1.jpg', caption: '桜', exif: { camera: 'Sony A7', iso: 400 } },
    { url: '/img/2.jpg', caption: '梅', exif: { camera: 'Canon R5', iso: 200 } },
  ],
};

CAP定理

分散システムでは、以下の3つのうち2つまでしか同時に満たせない。

    Consistency(一貫性)
        /\
       /  \
      /    \
     / CAP  \
    /________\
Availability    Partition Tolerance
(可用性)        (分断耐性)
組み合わせ特性
CP一貫性 + 分断耐性HBase, MongoDB (デフォルト)
AP可用性 + 分断耐性Cassandra, DynamoDB
CA一貫性 + 可用性単一ノードRDB(分散でない)

よくある間違い

間違い正しい判断
「スケールするからNoSQL」RDBもRead Replicaやパーティショニングでスケールする
「スキーマがないから楽」スキーマはアプリ層に移動するだけ。設計は必要
「NoSQLは速い」適切な設計のRDBも十分速い。用途次第
「RDBは時代遅れ」2024年でもRDBは最も信頼性の高いストア
「MongoDBは何でも使える」複雑なJOINが必要な場面ではRDBが適切

判断フローチャート

データに強い整合性が必要?
├── Yes → RDB(PostgreSQL, MySQL)
└── No
    ├── アクセスパターンは Key-Value 型?
    │   ├── Yes → Redis / DynamoDB
    │   └── No
    │       ├── データ構造が柔軟?
    │       │   ├── Yes → MongoDB
    │       │   └── No
    │       │       ├── 時系列データの大量書き込み?
    │       │       │   ├── Yes → Cassandra / TimescaleDB
    │       │       │   └── No
    │       │       │       └── 関係性の深い探索?
    │       │       │           ├── Yes → Neo4j
    │       │       │           └── No → RDB

まとめ

ポイント内容
判断基準データ特性とアクセスパターンで決める
RDBの強みACID、JOIN、SQL、成熟度
NoSQLの強みスケーラビリティ、柔軟性、特化性能
CAP定理分散システムの制約を理解する
組み合わせポリグロットパーシステンスで両方活用

理解度チェックリスト

  • RDBとNoSQLの特性の違いを5つ以上挙げられる
  • ユースケースに応じた適切なデータストアを選択できる
  • CAP定理を説明できる
  • 「NoSQLを選ぶべきではない」ケースを判断できる

次のステップ

次は演習:NoSQLで設計しよう。実際のシナリオに対して最適なNoSQLデータストアを選び、データモデルを設計する。


推定読了時間: 25分