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

コメント