データベース基礎
データベースとは何か
データベースとは、データを効率的に保存・管理・検索するための仕組みのこと。
身近な例で考えてみよう。図書館を想像してほしい。
図書館 = データベース
+---------------------------------------------------+
| 図書館(データベース) |
| |
| 書棚(テーブル) |
| +-----------------------------------------------+ |
| | 小説棚 | 技術書棚 | 雑誌棚 | 漫画棚 | |
| | (novels) | (tech) | (mags) | (comics) | |
| +-----------------------------------------------+ |
| |
| カード目録(インデックス) |
| +-----------------------------------------------+ |
| | タイトル順 | 著者順 | 出版年順 | ジャンル順 | |
| +-----------------------------------------------+ |
| |
| 図書カード(レコード/行) |
| +-----------------------------------------------+ |
| | ID: 001 | |
| | タイトル: データベース入門 | |
| | 著者: 山田太郎 | |
| | ISBN: 978-4-xxxx-xxxx-x | |
| | 棚番号: B-3-12 | |
| +-----------------------------------------------+ |
+---------------------------------------------------+
この対応関係を整理すると以下のようになる。
| 図書館の要素 | データベースの要素 | 説明 |
|---|---|---|
| 図書館全体 | データベース | データの集まり全体 |
| 書棚(ジャンル別) | テーブル | 同じ種類のデータをまとめた入れ物 |
| 図書カード1枚 | レコード(行) | 1件分のデータ |
| カードの記入項目 | カラム(列) | データの各項目(タイトル、著者など) |
| カード目録 | インデックス | 素早くデータを見つけるための索引 |
| 図書館のルール | 制約 | データの正しさを保つためのルール(必須項目など) |
カード目録がなければ、本を探すたびに全ての書棚を端から順に見ていく必要がある。データベースのインデックスも同じで、検索を高速にするための仕組みだ。
なぜデータベースが必要か
「ファイル(CSVやJSON)にデータを保存すればいいのでは?」と思うかもしれない。小規模なデータならそれでも問題ないが、アプリケーションが成長すると以下の問題が発生する。
ファイル管理 vs データベースの比較
| 課題 | ファイル管理 | データベース |
|---|---|---|
| 同時アクセス | 複数人が同時に編集するとデータが壊れる | ロック機構で安全に同時アクセスできる |
| データの整合性 | 矛盾したデータが入り放題 | 制約(NOT NULL、UNIQUEなど)で防止できる |
| 検索速度 | ファイルが大きくなると遅い | インデックスで高速検索が可能 |
| 障害時の復旧 | クラッシュするとデータが失われる | トランザクションログで復旧可能 |
| データの関連付け | ファイル間の関連を自分で管理する必要がある | 外部キーやJOINで簡単に関連付けできる |
| バックアップ・復元 | 手動でコピーするしかない | バックアップ・リストア機能が組み込まれている |
具体例: ユーザーデータの管理
CSVファイルでユーザーデータを管理する場合を考えてみよう。
users.csv:
id,name,email
1,田中太郎,taro@example.com
2,佐藤花子,hanako@example.com
orders.csv:
id,user_id,item,price
1,1,本,1500
2,1,ペン,200
この方式だと以下の問題が起きる。
- プログラムAがusers.csvを読み込んでいる最中に、プログラムBが書き込むとデータが壊れる
- user_id=999の注文データを入れてもエラーにならない(存在しないユーザー)
- 「田中太郎が買った商品の合計金額」を求めるには、2つのファイルを読み込んで自力で紐付ける必要がある
- users.csvが100万行になると検索が非常に遅い
データベースなら、これらの問題を全て解決できる。
ACID特性
ACID特性とは、データベースのトランザクション(一連の操作のまとまり)が満たすべき4つの性質のこと。信頼性のあるデータベースの基盤となる概念だ。
銀行振込の例で理解する
太郎の口座から花子の口座に1万円を送金する処理で考えてみよう。
操作1: 太郎の残高を1万円減らす(10万円 → 9万円)
操作2: 花子の残高を1万円増やす(5万円 → 6万円)
各特性の詳細
| 特性 | 英語 | 説明 | 銀行振込での例 |
|---|---|---|---|
| 原子性(Atomicity) | Atomicity | 全て成功するか、全て失敗するか。中途半端な状態にならない | 操作1だけ成功して操作2が失敗 → 両方ロールバック。太郎のお金は減らない |
| 一貫性(Consistency) | Consistency | トランザクション前後でデータの整合性が保たれる | 送金前の合計15万円 = 送金後の合計15万円。お金が増えたり消えたりしない |
| 独立性(Isolation) | Isolation | 同時に実行されるトランザクション同士が干渉しない | 太郎が花子に送金中に、次郎も花子に送金しても、金額がおかしくならない |
| 永続性(Durability) | Durability | COMMITされたデータは、障害が発生しても失われない | 送金完了後にサーバーが停電しても、花子の口座には1万円が入ったまま |
ACIDの図解
トランザクション(振込処理)
+------------------------------------------------------------------+
| |
| BEGIN |
| | |
| v |
| 操作1: 太郎の残高 -10,000円 |
| | |
| v |
| 操作2: 花子の残高 +10,000円 |
| | |
| +--- 成功 ---> COMMIT ---> 変更が確定(永続性) |
| | |
| +--- 失敗 ---> ROLLBACK ---> 全ての変更を取り消し(原子性) |
| |
+------------------------------------------------------------------+
独立性: 他のトランザクションからは、この処理の途中経過が見えない
一貫性: 処理前後で合計金額は変わらない
データベースの種類一覧と比較
データベースにはさまざまな種類があり、用途に応じて使い分ける。
リレーショナルデータベース(RDB)
データを**テーブル(表)として管理し、テーブル同士をリレーション(関連)**で結びつける。最も広く使われているタイプ。
| RDB | 特徴 | ライセンス | 主な採用企業 |
|---|---|---|---|
| PostgreSQL | 高機能、拡張性が高い、JSON対応 | PostgreSQLライセンス | Apple、Instagram、Spotify、Reddit |
| MySQL | 高速読み取り、Web開発で人気 | GPL / 商用 | Facebook、Twitter、YouTube |
| Oracle | エンタープライズ向け、高価 | 商用ライセンス | 銀行、保険、大企業 |
| SQL Server | Microsoft製、Windows環境に強い | 商用ライセンス | Microsoft系企業 |
| SQLite | ファイルベース、組み込み用途 | パブリックドメイン | モバイルアプリ、ブラウザ |
ドキュメントデータベース
データをJSON形式のドキュメントとして保存する。スキーマが柔軟で、アジャイル開発に向いている。
| ドキュメントDB | 特徴 | 主な用途 |
|---|---|---|
| MongoDB | 最も人気のあるNoSQLデータベース | Webアプリ、CMS、ログ収集 |
| Firestore | Google製、リアルタイム同期 | モバイルアプリ、チャット |
| CouchDB | オフライン同期に強い | モバイルアプリ |
RDBのデータ構造:
users テーブル
+----+--------+------------------+
| id | name | email |
+----+--------+------------------+
| 1 | 太郎 | taro@example.com |
+----+--------+------------------+
ドキュメントDBのデータ構造:
{
"_id": "user001",
"name": "太郎",
"email": "taro@example.com",
"address": {
"city": "東京",
"zip": "100-0001"
},
"hobbies": ["読書", "プログラミング"]
}
キーバリュー型データベース
**キー(名前)とバリュー(値)**のペアでデータを保存する。極めて高速で、キャッシュやセッション管理に使われる。
| キーバリューDB | 特徴 | 主な用途 |
|---|---|---|
| Redis | インメモリ、超高速 | キャッシュ、セッション、ランキング |
| DynamoDB | AWS製、フルマネージド、スケーラブル | サーバーレスアプリ、IoT |
| Memcached | シンプルなキャッシュ | Webアプリのキャッシュ |
キーバリューのイメージ:
+------------------------+-------------------+
| キー | バリュー |
+------------------------+-------------------+
| "user:1:name" | "太郎" |
| "session:abc123" | "{...セッション}" |
| "cache:top_products" | "[{...}, {...}]" |
+------------------------+-------------------+
グラフデータベース
データを**ノード(点)とエッジ(辺)**で表現する。関係性の分析に特化。
| グラフDB | 特徴 | 主な用途 |
|---|---|---|
| Neo4j | 最も人気のあるグラフDB | SNS、レコメンド、不正検知 |
| ArangoDB | マルチモデル対応 | 複合的なデータモデル |
グラフDBのイメージ:
(太郎) ---[友人]--> (花子)
| |
[購入] [購入]
| |
v v
(商品A) (商品B)
|
[類似]
|
v
(商品C)
→「太郎の友人が買った商品」「商品Aに似ている商品」を高速に検索できる
時系列データベース
時間順に並んだデータの保存と分析に特化。IoTセンサーデータやメトリクス収集に最適。
| 時系列DB | 特徴 | 主な用途 |
|---|---|---|
| InfluxDB | 時系列データ専用 | サーバー監視、IoT |
| TimescaleDB | PostgreSQL拡張 | メトリクス、金融データ |
| Prometheus | 監視に特化 | アプリケーション監視 |
全文検索エンジン
テキストの全文検索に特化したデータベース。形態素解析やあいまい検索が可能。
| 全文検索エンジン | 特徴 | 主な用途 |
|---|---|---|
| Elasticsearch | 最も人気、分散検索エンジン | ログ分析、サイト内検索 |
| OpenSearch | Elasticsearchのフォーク | AWS環境でのログ分析 |
| Meilisearch | 軽量、高速、簡単に使える | 小中規模のサイト内検索 |
CAP定理
分散データベースを設計する際の重要な理論。3つの性質のうち、同時に2つまでしか満たせないという定理。
3つの性質
| 性質 | 英語 | 説明 |
|---|---|---|
| 一貫性(C) | Consistency | 全てのノードが同じデータを返す |
| 可用性(A) | Availability | 全てのリクエストに応答を返す(エラーでも何か返す) |
| 分断耐性(P) | Partition Tolerance | ネットワーク障害が起きてもシステムが動作し続ける |
CAP定理の図解
一貫性 (C)
/\
/ \
/ \
/ CA \
/ 領域 \
/----------\
/ \
/ CP AP \
/ 領域 領域 \
/ \
+--------------------+
可用性 (A) 分断耐性 (P)
CA: PostgreSQL, MySQL(単一ノード)
→ ネットワーク分断が起きないことを前提とする
CP: MongoDB, Redis Cluster, HBase
→ 一貫性を優先し、分断時はリクエストを拒否する可能性がある
AP: DynamoDB, Cassandra, CouchDB
→ 可用性を優先し、一時的にデータが古い可能性がある
実務での考え方
インターネットを介した分散システムでは、ネットワーク分断は必ず起こる。そのため、実質的にはCPかAPのどちらかを選ぶことになる。
| ユースケース | 選択 | 理由 |
|---|---|---|
| 銀行の残高管理 | CP | データが間違っていたら大問題 |
| SNSのタイムライン | AP | 多少古いデータが見えても大きな問題はない |
| ECサイトの在庫管理 | CP | 在庫がないのに注文できたら問題 |
| ニュースフィード | AP | 数秒の遅延は許容される |
RDB vs NoSQL
使い分けフローチャート
データの構造は決まっているか?
├── はい → データ間に複雑な関連があるか?
│ ├── はい → RDB(PostgreSQL, MySQL)
│ └── いいえ → データ量は非常に大きいか?
│ ├── はい → NoSQL(DynamoDB, Cassandra)
│ └── いいえ → RDB(シンプルで十分)
│
└── いいえ → どんな検索が必要か?
├── キーで1件取得 → キーバリュー(Redis, DynamoDB)
├── 全文検索 → Elasticsearch
├── 関係性の探索 → グラフDB(Neo4j)
├── 時系列の集計 → 時系列DB(InfluxDB)
└── 柔軟な構造 → ドキュメントDB(MongoDB, Firestore)
比較表
| 比較項目 | RDB(PostgreSQL等) | ドキュメントDB(MongoDB等) | キーバリュー(Redis等) |
|---|---|---|---|
| データ構造 | テーブル(行と列) | JSON形式のドキュメント | キーとバリューのペア |
| スキーマ | 固定スキーマ(事前定義が必要) | スキーマレス(柔軟) | なし |
| 関連データ | JOINで結合 | 埋め込みまたは参照 | 非対応 |
| トランザクション | 強力(ACID完全対応) | 限定的(ドキュメント単位) | 限定的 |
| スケーリング | 垂直(スケールアップ)が基本 | 水平(スケールアウト)が容易 | 水平スケーリング対応 |
| 検索の柔軟性 | SQL(非常に柔軟) | クエリ言語(やや制限あり) | キー指定のみ |
| 学習コスト | SQLの習得が必要 | JSONの理解があれば始められる | 非常に低い |
| 代表的なユースケース | ECサイト、金融、業務システム | CMS、モバイルアプリ、IoT | キャッシュ、セッション管理 |
スキーマとスキーマレスの違い
スキーマあり(RDB)
スキーマとは、データの構造を事前に定義したもの。テーブルのカラム名、データ型、制約などを決めてからデータを投入する。
-- スキーマの定義(テーブル構造を先に決める)
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
age INTEGER CHECK (age >= 0)
);
-- スキーマに合わないデータは拒否される
INSERT INTO users (id, name, email, age) VALUES (1, '太郎', 'taro@example.com', 25); -- 成功
INSERT INTO users (id, name, email, age) VALUES (2, NULL, 'test@example.com', 25); -- 失敗(nameがNULL)
INSERT INTO users (id, name, email, age) VALUES (3, '花子', 'taro@example.com', 28); -- 失敗(emailが重複)
メリット: データの品質が保証される。型の不一致や必須項目の欠落を防げる。 デメリット: スキーマの変更(ALTER TABLE)が必要で、大規模テーブルでは時間がかかる場合がある。
スキーマレス(NoSQL)
データの構造を事前に定義しない。各ドキュメントが異なる構造を持てる。
// ドキュメント1
{
"name": "太郎",
"email": "taro@example.com",
"age": 25
}
// ドキュメント2(フィールドが異なる)
{
"name": "花子",
"email": "hanako@example.com",
"phone": "090-xxxx-xxxx",
"address": {
"city": "大阪",
"zip": "530-0001"
}
}
メリット: 柔軟にデータ構造を変更できる。開発初期の試行錯誤がしやすい。 デメリット: データの品質はアプリケーション側で保証する必要がある。
どちらを選ぶか
| 状況 | 推奨 |
|---|---|
| データ構造が明確で、変更が少ない | スキーマあり(RDB) |
| データ構造が頻繁に変わる | スキーマレス |
| データの整合性が重要 | スキーマあり(RDB) |
| 開発スピードを優先したい | スキーマレス |
| 複数のアプリケーションから同じDBを使う | スキーマあり(RDB) |
正規化 vs 非正規化
正規化とは
正規化とは、データの重複を排除してテーブルを効率的に設計する手法。データの一貫性を保ちやすくなる。
正規化前(非正規形):
+--------+--------+----------+--------+------+------+
| 注文ID | 顧客名 | 顧客住所 | 商品名 | 単価 | 数量 |
+--------+--------+----------+--------+------+------+
| 1 | 太郎 | 東京都 | 本A | 1500 | 2 |
| 1 | 太郎 | 東京都 | ペンB | 200 | 3 |
| 2 | 花子 | 大阪府 | 本A | 1500 | 1 |
+--------+--------+----------+--------+------+------+
問題: 「太郎」「東京都」が重複。太郎が引っ越したら全行を更新する必要がある。
正規化後:
顧客テーブル 商品テーブル 注文テーブル
+----+------+------+ +----+------+------+ +----+------+
| id | 名前 | 住所 | | id | 名前 | 単価 | | id | 顧客 |
+----+------+------+ +----+------+------+ +----+------+
| 1 | 太郎 | 東京 | | 1 | 本A | 1500 | | 1 | 1 |
| 2 | 花子 | 大阪 | | 2 | ペンB| 200 | | 2 | 2 |
+----+------+------+ +----+------+------+ +----+------+
注文明細テーブル
+------+------+------+
| 注文 | 商品 | 数量 |
+------+------+------+
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 2 | 1 | 1 |
+------+------+------+
非正規化とは
意図的にデータの重複を許容して、読み取り性能を向上させる手法。
非正規化の例(注文履歴テーブル):
+--------+--------+--------+------+------+
| 注文ID | 顧客名 | 商品名 | 単価 | 数量 |
+--------+--------+--------+------+------+
| 1 | 太郎 | 本A | 1500 | 2 |
| 1 | 太郎 | ペンB | 200 | 3 |
+--------+--------+--------+------+------+
→ JOINなしで注文内容を一発で取得できる(読み取りが速い)
→ ただし「太郎」が重複しているので、更新が面倒
いつどちらを選ぶか
| 状況 | 推奨 | 理由 |
|---|---|---|
| 通常の業務アプリケーション | 正規化 | データの一貫性が重要 |
| 読み取りが極端に多い(レポート、分析) | 非正規化 | JOINのコストを避けて読み取り速度を上げる |
| データの更新が多い | 正規化 | 更新箇所を最小化できる |
| リアルタイム分析、ダッシュボード | 非正規化 | 事前に集計したデータを保持 |
| 小中規模のアプリケーション | 正規化 | まず正規化から始めるのが基本 |
| 大規模アクセスのWebサービス | 両方併用 | 正規化したテーブル + 非正規化したキャッシュ層 |
実務での基本方針: まず正規化で設計し、パフォーマンスが問題になった箇所だけ非正規化を検討する。
トランザクション分離レベル
複数のトランザクションが同時に実行されるとき、他のトランザクションの変更がどこまで見えるかを決める設定。
発生しうる問題
| 問題 | 英語 | 説明 |
|---|---|---|
| ダーティリード | Dirty Read | 他のトランザクションのCOMMIT前のデータが見える |
| ノンリピータブルリード | Non-repeatable Read | 同じクエリを2回実行すると、別の結果が返る(他が更新した) |
| ファントムリード | Phantom Read | 同じ条件で検索すると、行数が変わる(他が挿入/削除した) |
分離レベルの比較表
| 分離レベル | ダーティリード | ノンリピータブルリード | ファントムリード | パフォーマンス |
|---|---|---|---|---|
| READ UNCOMMITTED | 発生する | 発生する | 発生する | 最速 |
| READ COMMITTED | 防止 | 発生する | 発生する | 速い |
| REPEATABLE READ | 防止 | 防止 | 発生する | やや遅い |
| SERIALIZABLE | 防止 | 防止 | 防止 | 最も遅い |
各レベルの解説
READ UNCOMMITTED(未コミット読み取り)
他のトランザクションがCOMMITしていないデータも読める。最も緩い分離レベル。
トランザクションA トランザクションB
BEGIN;
UPDATE users SET age=30 BEGIN;
WHERE id=1;
SELECT age FROM users WHERE id=1;
→ 30が見える(まだCOMMITしていない!)
ROLLBACK;
→ 30を使って処理を進めてしまう
(実際にはROLLBACKされて元の値に戻った)
READ COMMITTED(コミット済み読み取り)
PostgreSQLのデフォルト。COMMITされたデータのみ読める。
トランザクションA トランザクションB
BEGIN; BEGIN;
UPDATE users SET age=30 SELECT age FROM users WHERE id=1;
WHERE id=1; → 25(COMMIT前なので古い値)
COMMIT;
SELECT age FROM users WHERE id=1;
→ 30(COMMITされたので新しい値)
※同じクエリなのに結果が変わる!
REPEATABLE READ(反復読み取り)
トランザクション開始時のスナップショットを使う。同じクエリは常に同じ結果を返す。
トランザクションA トランザクションB
BEGIN;
SELECT age FROM users WHERE id=1;
→ 25
BEGIN;
UPDATE users SET age=30
WHERE id=1;
COMMIT;
SELECT age FROM users WHERE id=1;
→ 25(スナップショットなので変わらない)
COMMIT;
SERIALIZABLE(直列化可能)
最も厳格。トランザクションを1つずつ順番に実行したのと同じ結果を保証する。
実務での選び方
| ユースケース | 推奨レベル | 理由 |
|---|---|---|
| 一般的なWebアプリケーション | READ COMMITTED | バランスが良い(PostgreSQLのデフォルト) |
| レポート生成 | REPEATABLE READ | 一貫したデータでレポートを作成 |
| 金融取引 | SERIALIZABLE | 絶対にデータの不整合を許さない |
| ログ書き込み | READ COMMITTED | 多少の不整合は許容される |
インデックスの基本
インデックスとは
インデックスとは、データベースの検索を高速化するための仕組み。本の巻末にある「索引」と同じ考え方だ。
本の索引の例:
+------------------+--------+
| キーワード | ページ |
+------------------+--------+
| ACID | 45 |
| インデックス | 78 |
| カーソル | 112 |
| トランザクション | 45, 93 |
+------------------+--------+
→ 「トランザクション」を調べたいとき
索引なし: 1ページ目から順に読む(遅い)
索引あり: 索引を見て45ページと93ページに直行(速い)
B-treeインデックス
最も一般的なインデックスの種類。ほとんどのRDBでデフォルトで使われる。
B-tree(バランスツリー)の構造:
[50]
/ \
[20,35] [70,85]
/ | \ / | \
[10] [25] [40] [60] [75] [90]
| | | | | |
行 行 行 行 行 行
検索例: id=60 を探す場合
1. ルート [50] → 60 > 50 なので右へ
2. [70,85] → 60 < 70 なので左の子へ
3. [60] → 見つかった!
→ 100万行あっても、20回程度の比較で見つかる(log2(1000000) ≒ 20)
なぜ検索が速くなるか
| 検索方法 | 100万行での比較回数 | 時間計算量 |
|---|---|---|
| 全件スキャン(索引なし) | 最大100万回 | O(n) |
| B-treeインデックス | 約20回 | O(log n) |
注意点: インデックスは検索を速くするが、データの挿入・更新・削除のたびにインデックスも更新する必要があるため、書き込みは遅くなる。
インデックスを作るべき場面
| 場面 | 理由 |
|---|---|
| WHERE句で頻繁に使うカラム | 検索条件のカラムにインデックスがあると速い |
| JOINの結合条件に使うカラム | 外部キーにはインデックスを作るのが基本 |
| ORDER BYで使うカラム | ソートが高速化される |
| UNIQUEが必要なカラム | UNIQUEインデックスで一意性を保証 |
インデックスを作らない方がよい場面
| 場面 | 理由 |
|---|---|
| テーブルが小さい(数百行以下) | 全件スキャンでも十分速い |
| INSERT/UPDATEが非常に多いカラム | インデックスの更新コストが高くなる |
| カーディナリティが低いカラム | true/falseなど値の種類が少ないとインデックスの効果が薄い |
| ほとんど検索に使わないカラム | 使わないインデックスは無駄なストレージ消費 |
データベース選定の判断基準
新しいプロジェクトでデータベースを選ぶ際のチェックリスト。
チェックリスト
| チェック項目 | 考慮事項 |
|---|---|
| データの構造は明確か | 明確 → RDB、不明確 → ドキュメントDB |
| トランザクションは必要か | 必要 → RDB(ACID準拠) |
| 読み取りと書き込みの比率は | 読み取り重視 → キャッシュ層を検討 |
| スケーリング要件は | 水平スケーリング → NoSQL、垂直 → RDB |
| チームの技術スタック | SQLの経験が豊富 → RDB、Node.jsメイン → MongoDB/Firestore |
| 予算とコスト | OSS(PostgreSQL, MySQL)→ 無料、クラウドDB → 従量課金 |
| 運用・保守のしやすさ | マネージドサービス(RDS, Cloud SQL等)→ 運用負荷が低い |
| データの関連性 | 複雑な関連 → RDB、シンプル → NoSQL |
| レイテンシ要件 | 超低レイテンシ → Redis、通常 → RDB |
| データ量の見込み | TB以上 → 分散DB(DynamoDB, Cassandra等)を検討 |
よくある構成パターン
パターン1: 一般的なWebアプリケーション
+-----------------+ +--------+
| アプリケーション | --> | PostgreSQL |
+-----------------+ +--------+
パターン2: キャッシュ層あり
+-----------------+ +-------+ +------------+
| アプリケーション | --> | Redis | --> | PostgreSQL |
+-----------------+ +-------+ +------------+
(キャッシュ) (メインDB)
パターン3: 検索機能あり
+-----------------+ +------------+ +---------------+
| アプリケーション | --> | PostgreSQL | --> | Elasticsearch |
+-----------------+ +------------+ +---------------+
(メインDB) (全文検索)
パターン4: マイクロサービス
+-----------+ +-------+
| サービスA | --> | PostgreSQL |
+-----------+ +-------+
+-----------+ +---------+
| サービスB | --> | MongoDB |
+-----------+ +---------+
+-----------+ +-------+
| サービスC | --> | Redis |
+-----------+ +-------+
主要データベース比較表
以下は、現在よく使われている主要なデータベースの比較表。
| 項目 | PostgreSQL | MySQL | MongoDB | DynamoDB | Redis | Supabase | Firebase Firestore |
|---|---|---|---|---|---|---|---|
| 種類 | RDB | RDB | ドキュメントDB | キーバリュー/ドキュメント | キーバリュー | RDB(PostgreSQL) | ドキュメントDB |
| ライセンス | PostgreSQLライセンス | GPL / 商用 | SSPL | プロプライエタリ | BSD | Apache 2.0 | プロプライエタリ |
| スケーリング方式 | 垂直 + 論理レプリケーション | 垂直 + レプリケーション | 水平シャーディング | 自動水平スケーリング | クラスタリング | Supabaseが管理 | 自動水平スケーリング |
| トランザクション | ACID完全対応 | ACID(InnoDB) | マルチドキュメント対応 | 限定的 | 限定的 | ACID完全対応 | 限定的 |
| JSON対応 | JSONB(高速) | JSON型 | ネイティブ | ネイティブ | JSON対応 | JSONB(高速) | ネイティブ |
| 全文検索 | 内蔵(tsvector) | FULLTEXT INDEX | Atlas Search | なし | RediSearch | 内蔵(PostgreSQL) | なし |
| 学習曲線 | やや高い | 普通 | 低い | やや高い | 低い | 低い(GUI充実) | 低い(SDK充実) |
| 料金 | 無料(OSS) | 無料(OSS) | 無料枠あり / 従量課金 | 従量課金 | 無料(OSS) | 無料枠あり / 従量課金 | 無料枠あり / 従量課金 |
| ホスティング | セルフ / RDS / Cloud SQL | セルフ / RDS / PlanetScale | Atlas / セルフ | AWSのみ | セルフ / ElastiCache | Supabase Cloud | Firebaseのみ |
| 採用企業 | Apple, Instagram, Spotify | Facebook, YouTube, Twitter | Adobe, Forbes | Amazon, Netflix | Twitter, GitHub | 多数のスタートアップ | Google系企業 |
| 強み | 機能の豊富さ、拡張性 | 読み取り性能、エコシステム | 柔軟性、スケーラビリティ | 完全マネージド、スケーラビリティ | 超高速、データ構造が豊富 | 開発体験、認証・ストレージ統合 | リアルタイム同期、SDK |
| 弱み | 水平スケーリングの難しさ | 機能がPostgreSQLより少ない | トランザクションの制限 | 柔軟性の低さ | 永続化の制約 | PostgreSQLの制約を継承 | 複雑なクエリが苦手 |
選定の目安
| ユースケース | 推奨DB |
|---|---|
| 一般的なWebアプリ | PostgreSQL / Supabase |
| モバイルアプリ(リアルタイム同期) | Firebase Firestore |
| 大規模ECサイト | PostgreSQL + Redis |
| サーバーレスアプリ | DynamoDB / Firestore |
| キャッシュ / セッション管理 | Redis |
| CMS / ブログ | PostgreSQL / MongoDB |
| ログ分析 | Elasticsearch |
| プロトタイプ / MVP | Supabase / Firebase |
まとめ
データベースの基礎知識を振り返ろう。
| 概念 | ポイント |
|---|---|
| データベースとは | データを効率的に保存・管理・検索する仕組み |
| ACID特性 | 原子性、一貫性、独立性、永続性でデータの信頼性を保証 |
| CAP定理 | 分散システムではC, A, Pのうち2つしか同時に満たせない |
| RDB vs NoSQL | 構造化データ + 関連 → RDB、柔軟性 + スケーラビリティ → NoSQL |
| 正規化 | データの重複を排除して整合性を保つ(基本はこちら) |
| 非正規化 | 読み取り性能のために意図的に重複を許容する |
| トランザクション分離 | 同時アクセス時のデータの見え方を制御するレベル設定 |
| インデックス | B-treeなどの構造で検索を高速化する(ただし書き込みは遅くなる) |
データベースの選定に「正解」はない。プロジェクトの要件、チームのスキル、将来の成長を考慮して、最適なものを選ぶことが重要だ。迷ったらPostgreSQLから始めるのがよい。RDBの機能が充実しており、JSONBでドキュメントDBのような使い方もでき、無料で利用できる。