元RDBMS経験者が困ったFirestoreでのデータベース設計


RDB経験者がFirestoreで陥る「致命的なワナ」

  • OracleSQL、PostgreSQLなどのRDBで設計スキルを磨いてきたエンジニアにとって、Firestoreの思想は真逆です。
  • RDB設計での「正規化命!JOINで解決」という常識を持ち込んでFirestoreのデータ設計を行うと、データ設計が非効率になり、読み取り課金による月額料金が跳ね上がる事態を招きます。
  • 本記事の目的: RDB経験者がFirestoreで失敗しないために、データベースの作り方の違いについて具体例を用いて説明いたします。

RDBとFirestoreでの決定的な違い

そもそも、FirestoreはNoSQL(ノースケール)に分類されるドキュメントデータベースです。RDBとNoSQLの違いをまとめると以下になります。

項目RDB(Oracle SQL等)NoSQL(Firestore)
分類リレーショナルデータベースドキュメントデータベース
データ構造テーブル(表形式)。行と列で構成され、厳密なスキーマを持つ。コレクションとドキュメント。JSONに似たデータ構造(マップや配列)を持つ。
データ間の関係JOINによってテーブルを結合し、データを取得する(正規化を基本とする)。JOINの概念がない。データをドキュメント内に埋め込み(非正規化)、読み取り回数を減らす。
得意な処理複雑なトランザクション、データの厳密な整合性、柔軟なクエリ。大規模なスケーラビリティ、リアルタイム同期、高速な読み取り処理。

上記の点を踏まえて、同じユースケースでRDB、NoSQLでデータベースを作成した時の設計の違いを確認してみましょう。

RDBとNoSQLでのデータベース設計の具体的な違い

1. RDB(MySQL/PostgreSQLなど)での設計

まず、RDBの設計がどのようにデータを分解しているかを確認します。ブログのコメント機能についてRDBで正規化されたテーブルを確認します。

ユースケース: 読者がブログの記事詳細ページにアクセスした際、記事情報、著者情報、コメント一覧を高速で表示させる。

テーブル名カラム (フィールド)目的
posts (記事)post_id (PK), title, user_id (FK), content記事本体の情報
users (ユーザー)user_id (PK), user_name投稿者の情報
comments (コメント)comment_id (PK), post_id (FK), user_id (FK), text, created_atコメントの内容
-- 記事情報取得
SELECT
    -- 記事の基本情報
    P.title AS article_title,
    P.content AS article_content,
    -- 記事の著者情報
    A.user_name AS author_name,
    -- コメント情報
    C.text AS comment_text,
    C.created_at AS comment_time,
    -- コメント投稿者情報
    U.user_name AS commenter_name
FROM
    posts P
-- 1. 記事の著者(Author)情報を結合
INNER JOIN
    users A ON P.user_id = A.user_id
-- 2. コメント一覧を結合
LEFT JOIN
    comments C ON P.post_id = C.post_id
-- 3. コメントの投稿者(User)情報を結合
LEFT JOIN
    users U ON C.user_id = U.user_id
WHERE
    P.post_id = 'POST01'
ORDER BY
    C.created_at ASC;

上記のようにRDBでは、データの一貫性と重複排除を最優先し、データを複数のテーブルに分割し、外部キー(Foreign Key)で関連付けます。

2. Firestore(NoSQL)での設計:非正規化を重視

コレクション名ドキュメント構造目的
posts (記事)post_id, title, author_name, content記事の著者名も埋め込み
users (ユーザー)user_id, nameユーザーのマスターデータ。
comments (コメント)post_id, text, created_at, user_nameコメント本体に加え、投稿者の情報を直接埋め込む(非正規化)
例:テスト太郎(USER01)の記事に対して、テスト次郎(USER02)がコメントした場合

posts(記事)コレクション

{
“post_id”: “POST01”,
“title”: “テスト記事”,
“author_name”: “テスト太郎”,
“content”: “テスト記事です。”
}

users(ユーザー)テーブル

{
“user_id”: “USER01”,
“nama”: “テスト太郎”
}
{
“user_id”: “USER02”,
“nama”: “テスト次郎”
}

comments(コメント)テーブル

{
“post_id”: “POST01”,
“text”: “テストコメント”
“created_at”: “2025/10/22”,
“user_name”: “テスト次郎”
}

Firestoreでは、JOINの概念が存在せず、「読み取り回数の最小化」と「取得したいデータセットの定義」を最優先します。そのため、データを積極的に重複させます。

コメント

タイトルとURLをコピーしました