- Published on
データベース完全比較2025:PostgreSQL vs MySQL vs MongoDB vs Redis — 選定基準と実践ガイド
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- 1. 2025年データベースランキングとトレンド
- 2. RDBMS vs NoSQL vs NewSQL — いつ何を使うべきか
- 3. PostgreSQLディープダイブ
- 4. MySQLディープダイブ
- 5. MongoDBディープダイブ
- 6. Redisディープダイブ
- 7. DynamoDB — サーバーレスNoSQLの代表
- 8. Cassandra / ScyllaDB — 大規模書き込みの王
- 9. 性能ベンチマーク比較
- 10. ユースケース別選択マトリックス
- 11. マルチDBアーキテクチャパターン
- 12. コスト比較(マネージドサービス)
- 13. 面接質問20選
- 14. クイズ
- 参考資料
はじめに
2025年のデータベースエコシステムは、これまで以上に多様で複雑です。AI/MLワークロードの爆発的な増加によりベクトル検索が必須となり、リアルタイムストリーミング処理、マルチモデル対応、サーバーレスアーキテクチャなどの新しい要件がデータベース選定をさらに困難にしています。
この記事では、PostgreSQL、MySQL、MongoDB、Redisを中心に、DynamoDB、Cassandra/ScyllaDBまで8つの主要データベースのアーキテクチャ、性能、コスト、ユースケースを体系的に比較します。単純な機能の羅列ではなく、実際のプロダクション環境での意思決定に役立つ実践ガイドを提供します。
1. 2025年データベースランキングとトレンド
DB-Enginesランキング(2025年3月時点)
| 順位 | データベース | 種類 | スコア | 前年比 |
|---|---|---|---|---|
| 1 | Oracle | RDBMS | 1,245 | -3.2% |
| 2 | MySQL | RDBMS | 1,142 | -1.8% |
| 3 | PostgreSQL | RDBMS | 685 | +12.4% |
| 4 | MongoDB | Document | 397 | +2.1% |
| 5 | Redis | Key-Value | 168 | -5.3% |
| 6 | Elasticsearch | Search | 155 | +1.7% |
| 7 | SQLite | RDBMS | 142 | +8.9% |
| 8 | Cassandra | Wide-Column | 112 | -4.1% |
2025年の主要トレンド
1. AIがデータベース選定を変える
RAG(Retrieval-Augmented Generation)パイプラインが普及し、ベクトル検索機能がデータベース選定の核心基準となりました。PostgreSQLのpgvector、MongoDB Atlas Vector Search、Redis Stackがこの競争で頭角を現しています。
2. サーバーレスデータベースの台頭
Neon(PostgreSQLサーバーレス)、PlanetScale(MySQLサーバーレス)、MongoDB Atlas Serverless、DynamoDB on-demandなど、使用量ベースの課金モデルが標準になりつつあります。
3. マルチモデルデータベース
一つのデータベースでリレーショナル、ドキュメント、グラフ、時系列データを全て処理するマルチモデルアプローチが増加しています。PostgreSQLがJSONB、pgvector、PostGISなどの拡張でこの分野をリードしています。
4. Valkeyの登場
Redis Labsのライセンス変更(SSPL)に対応して、Linux FoundationがValkeyフォークをリリースしました。AWS ElastiCache、Google Cloud Memorystoreなどの採用により、Redisエコシステムに大きな変化が起きています。
2. RDBMS vs NoSQL vs NewSQL — いつ何を使うべきか
CAP定理の実践的理解
分散システムでConsistency(一貫性)、Availability(可用性)、Partition Tolerance(分断耐性)の3つを同時に完璧に達成できないという理論です。
Consistency (C)
/\
/ \
/ \
CP / CAP \ CA
system/ 不可能 \ system
/________\
Partition(P) Availability(A)
| 種類 | 組み合わせ | データベース | 特徴 |
|---|---|---|---|
| CA | 一貫性 + 可用性 | 伝統的RDBMS(単一ノード) | ネットワーク分断時は利用不可 |
| CP | 一貫性 + 分断耐性 | MongoDB, HBase | 可用性の一部を犠牲 |
| AP | 可用性 + 分断耐性 | Cassandra, DynamoDB | 結果整合性 |
RDBMSを選ぶべき時
- トランザクション整合性が必須(金融、決済、在庫管理)
- 複雑なJOINと集計クエリが頻繁
- データスキーマが明確で安定的
- ACID準拠が法的/規制的要件
NoSQLを選ぶべき時
- スキーマが頻繁に変更される、または非構造化データ
- 水平スケーリングが核心要件
- 超低遅延(サブミリ秒)の読み書きが必要
- 大容量データの高速書き込み処理
NewSQLを選ぶべき時
CockroachDB、TiDB、YugabyteDBなどのNewSQLデータベースは、RDBMSのトランザクション保証とNoSQLの水平スケーラビリティを両方提供します。
- グローバル分散が必要なトランザクションシステム
- RDBMS互換性を維持しながら水平スケーリングが必要
- ただし、成熟度とコミュニティ規模で伝統的RDBMSにはまだ不足
3. PostgreSQLディープダイブ
アーキテクチャ概要
PostgreSQLはプロセスベースのアーキテクチャを使用します。各クライアント接続に専用のバックエンドプロセスが割り当てられます。
┌─────────────────────────────────────────────┐
│ PostgreSQL │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Backend │ │ Backend │ │ Backend │ │
│ │ Process │ │ Process │ │ Process │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────┴─────────────┴─────────────┴────┐ │
│ │ Shared Memory │ │
│ │ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ Shared │ │ WAL │ │ │
│ │ │ Buffers │ │ Buffers │ │ │
│ │ └──────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ Background Workers │ │
│ │ WAL Writer | Checkpointer | │ │
│ │ Autovacuum | Stats Collector │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
MVCC(Multi-Version Concurrency Control)
PostgreSQLのMVCCは各行の複数バージョンを維持し、読み取り/書き込み間のロック競合を最小化します。
-- トランザクション分離レベル設定
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- MVCC動作確認
BEGIN;
SELECT xmin, xmax, ctid, * FROM orders WHERE id = 1;
-- xmin: 作成トランザクションID, xmax: 削除トランザクションID
-- ctid: 物理的位置 (page, offset)
COMMIT;
JSONB — リレーショナル + ドキュメントの最強の組み合わせ
-- JSONBカラムの作成
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
metadata JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- GINインデックス作成(JSONB検索最適化)
CREATE INDEX idx_products_metadata ON products USING GIN (metadata);
-- JSONBクエリ例
SELECT name, metadata->>'category' AS category,
(metadata->'specs'->>'weight')::numeric AS weight
FROM products
WHERE metadata @> '{"category": "electronics"}'
AND (metadata->'specs'->>'weight')::numeric < 500;
-- JSONB集計
SELECT metadata->>'category' AS category,
COUNT(*),
AVG((metadata->'price'->>'amount')::numeric) AS avg_price
FROM products
GROUP BY metadata->>'category';
pgvector — AI/RAG時代のゲームチェンジャー
-- pgvector拡張のインストール
CREATE EXTENSION IF NOT EXISTS vector;
-- ベクトルカラムを持つテーブル
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
embedding vector(1536) -- OpenAI text-embedding-3-small次元
);
-- HNSWインデックス(高速近似最近傍探索)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
-- IVFFlatインデックス(メモリ効率的)
CREATE INDEX ON documents
USING ivfflat (embedding vector_l2_ops)
WITH (lists = 100);
-- コサイン類似度ベースの検索
SELECT id, title,
1 - (embedding <=> query_embedding) AS similarity
FROM documents
ORDER BY embedding <=> query_embedding
LIMIT 10;
-- ハイブリッド検索(ベクトル + 全文検索)
SELECT id, title,
ts_rank(to_tsvector('japanese', content), plainto_tsquery('japanese', 'search')) AS text_score,
1 - (embedding <=> query_embedding) AS vector_score
FROM documents
WHERE to_tsvector('japanese', content) @@ plainto_tsquery('japanese', 'search')
ORDER BY vector_score * 0.7 + text_score * 0.3 DESC
LIMIT 10;
パーティショニング
-- 範囲パーティショニング例
CREATE TABLE orders (
id BIGSERIAL,
order_date DATE NOT NULL,
customer_id INTEGER NOT NULL,
total_amount NUMERIC(10,2),
PRIMARY KEY (id, order_date)
) PARTITION BY RANGE (order_date);
-- パーティション作成
CREATE TABLE orders_2025_q1 PARTITION OF orders
FOR VALUES FROM ('2025-01-01') TO ('2025-04-01');
CREATE TABLE orders_2025_q2 PARTITION OF orders
FOR VALUES FROM ('2025-04-01') TO ('2025-07-01');
-- 自動パーティション管理(pg_partman)
CREATE EXTENSION pg_partman;
SELECT partman.create_parent(
p_parent_table => 'public.orders',
p_control => 'order_date',
p_type => 'native',
p_interval => '3 months'
);
PostgreSQL 17の主要機能
- Incremental Backup: pg_basebackupでの増分バックアップサポート
- SQL/JSON標準サポート強化: JSON_TABLE、JSON_QUERY等
- 性能向上: 並列ハッシュ結合の改善、バルクローディング最適化
- セキュリティ強化: LDAP/SCRAM認証の改善
4. MySQLディープダイブ
InnoDBアーキテクチャ
┌─────────────────────────────────────────────┐
│ MySQL Server │
│ ┌───────────────────────────────────────┐ │
│ │ Connection Pool │ │
│ │ Thread 1 | Thread 2 | Thread N │ │
│ └───────────────────────────────────────┘ │
│ ┌───────────────────────────────────────┐ │
│ │ Query Cache(8.0+で廃止) │ │
│ │ Parser -> Optimizer │ │
│ └───────────────────────────────────────┘ │
│ ┌───────────────────────────────────────┐ │
│ │ InnoDB Engine │ │
│ │ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ Buffer │ │ Change Buffer │ │ │
│ │ │ Pool │ │ │ │ │
│ │ └──────────┘ └──────────────────┘ │ │
│ │ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ Redo Log │ │ Undo Log │ │ │
│ │ └──────────┘ └──────────────────┘ │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
MySQLはスレッドベースのアーキテクチャで、PostgreSQLのプロセスベースと対比されます。接続オーバーヘッドが低く、メモリ効率が高いです。
HeatWave ML — MySQLで直接ML
-- HeatWave MLでモデル学習
CALL sys.ML_TRAIN('my_schema.customer_data',
'churn_label',
JSON_OBJECT('task', 'classification'),
@model_handle);
-- 予測実行
CALL sys.ML_PREDICT_ROW(
JSON_OBJECT('age', 35, 'tenure', 24, 'monthly_charge', 79.99),
@model_handle,
@prediction);
SELECT @prediction;
Group Replication(グループレプリケーション)
-- Group Replicationステータス確認
SELECT MEMBER_ID, MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE
FROM performance_schema.replication_group_members;
-- シングルプライマリモード(デフォルト、推奨)
SET GLOBAL group_replication_single_primary_mode = ON;
ProxySQLで読み書き分離
-- ProxySQLルーティングルール設定
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup)
VALUES
(1, 1, '^SELECT .* FOR UPDATE', 0), -- 書き込みグループ
(2, 1, '^SELECT', 1); -- 読み取りグループ
-- サーバーグループ設定
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight)
VALUES
(0, 'primary.mysql.local', 3306, 1), -- 書き込み
(1, 'replica1.mysql.local', 3306, 50), -- 読み取り
(1, 'replica2.mysql.local', 3306, 50); -- 読み取り
5. MongoDBディープダイブ
ドキュメントモデルの強み
// MongoDBドキュメント構造 — 埋め込みパターン
db.orders.insertOne({
orderId: 'ORD-2025-001',
customer: {
name: '田中太郎',
email: 'tanaka@example.com',
address: {
street: '渋谷区神宮前1-2-3',
city: '東京',
zipCode: '150-0001',
},
},
items: [
{
productId: 'PROD-001',
name: 'ワイヤレスキーボード',
price: 8900,
quantity: 2,
},
{
productId: 'PROD-002',
name: 'モニタースタンド',
price: 4500,
quantity: 1,
},
],
payment: {
method: 'card',
status: 'completed',
paidAt: ISODate('2025-03-15T10:30:00Z'),
},
totalAmount: 22300,
createdAt: ISODate('2025-03-15T10:25:00Z'),
})
Atlas Vector Search
// ベクトル検索インデックス作成
db.collection.createSearchIndex({
name: 'vector_index',
definition: {
mappings: {
dynamic: true,
fields: {
embedding: {
type: 'knnVector',
dimensions: 1536,
similarity: 'cosine',
},
},
},
},
})
// ベクトル検索クエリ
db.documents.aggregate([
{
$vectorSearch: {
index: 'vector_index',
path: 'embedding',
queryVector: queryEmbedding, // 1536次元ベクトル
numCandidates: 100,
limit: 10,
filter: { category: 'tech' },
},
},
{
$project: {
title: 1,
content: 1,
score: { $meta: 'vectorSearchScore' },
},
},
])
MongoDBシャーディング
// シャードキー選択 — カーディナリティ、分散度、クエリパターンを考慮
sh.enableSharding('ecommerce')
// ハッシュシャーディング(均等分散)
sh.shardCollection('ecommerce.orders', { customerId: 'hashed' })
// 範囲シャーディング(範囲クエリ最適化)
sh.shardCollection('ecommerce.logs', { timestamp: 1 })
// ゾーンシャーディング(地域ベースのデータ分離)
sh.addShardTag('shard-jp', 'ASIA')
sh.addShardTag('shard-us', 'AMERICAS')
sh.addTagRange('ecommerce.users', { region: 'JP' }, { region: 'JQ' }, 'ASIA')
6. Redisディープダイブ
データ構造と活用
-- Strings: キャッシュ、セッション、カウンター
SET user:session:abc123 "session_data" EX 3600
INCR page:views:homepage
-- Hashes: オブジェクト格納
HSET user:1001 name "田中太郎" email "tanaka@dev.com" login_count 42
HINCRBY user:1001 login_count 1
-- Sorted Sets: リーダーボード、ランキング
ZADD leaderboard 9500 "player:alice"
ZADD leaderboard 8700 "player:bob"
ZADD leaderboard 9200 "player:charlie"
ZREVRANGE leaderboard 0 9 WITHSCORES -- Top 10
-- Streams: イベントストリーミング
XADD mystream * sensor_id "temp-01" temperature "23.5" humidity "45"
XREAD COUNT 10 BLOCK 5000 STREAMS mystream 0
-- HyperLogLog: 概算ユニークカウント
PFADD unique:visitors:2025-03-23 "user1" "user2" "user3"
PFCOUNT unique:visitors:2025-03-23
Redis Stack — Search, JSON, TimeSeries
-- Redis JSON
JSON.SET product:001 $ '{"name":"ワイヤレスキーボード","price":8900,"tags":["electronics","keyboard"],"specs":{"weight":350,"wireless":true}}'
JSON.GET product:001 $.specs.weight
-- Redis Searchインデックス作成
FT.CREATE idx:products ON JSON PREFIX 1 product:
SCHEMA
$.name AS name TEXT SORTABLE
$.price AS price NUMERIC SORTABLE
$.tags[*] AS tags TAG
$.specs.weight AS weight NUMERIC
-- 全文検索
FT.SEARCH idx:products "@name:keyboard @price:[5000 10000]"
-- ベクトル検索(Redis Stack)
FT.CREATE idx:docs ON HASH PREFIX 1 doc:
SCHEMA
title TEXT
embedding VECTOR HNSW 6 TYPE FLOAT32 DIM 1536 DISTANCE_METRIC COSINE
-- KNN検索
FT.SEARCH idx:docs "*=>[KNN 10 @embedding $query_vec AS score]"
PARAMS 2 query_vec "\x00\x00..."
SORTBY score
RETURN 2 title score
永続化: RDB vs AOF
| 特性 | RDB(スナップショット) | AOF(Append Only File) |
|---|---|---|
| 動作方式 | 定期的なメモリダンプ | 全書き込みコマンドの記録 |
| データ損失 | 最後のスナップショット以降 | fsyncポリシーに依存 |
| 復旧速度 | 高速(バイナリロード) | 低速(コマンド再実行) |
| ファイルサイズ | 小さい(圧縮) | 大きい(全コマンド記録) |
| CPU影響 | fork()時に高い | everysecで低い |
Valkeyフォーク — Redisの未来?
| 項目 | Redis | Valkey |
|---|---|---|
| ライセンス | SSPL(2024~) | BSD-3-Clause |
| クラウドサポート | Redis Cloud | AWS, GCP, Azure |
| 互換性 | オリジナル | Redis 7.2互換 |
| 開発主体 | Redis Ltd. | Linux Foundation |
| コミュニティ | 制限的な貢献 | オープン貢献 |
7. DynamoDB — サーバーレスNoSQLの代表
Single-Table Designパターン
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('EcommerceTable')
# ユーザープロファイル保存
table.put_item(Item={
'PK': 'USER#001',
'SK': 'PROFILE',
'name': '田中太郎',
'email': 'tanaka@dev.com',
'type': 'USER'
})
# 同じテーブルに注文を保存
table.put_item(Item={
'PK': 'USER#001',
'SK': 'ORDER#2025-03-15#ORD001',
'items': [{'name': 'キーボード', 'price': 8900}],
'total': 8900,
'status': 'completed',
'type': 'ORDER'
})
# ユーザーの全注文を照会(Query)
response = table.query(
KeyConditionExpression='PK = :pk AND begins_with(SK, :sk)',
ExpressionAttributeValues={
':pk': 'USER#001',
':sk': 'ORDER#'
}
)
DynamoDB料金モデル
| モード | 読み取りコスト | 書き込みコスト | 適合するケース |
|---|---|---|---|
| On-Demand | 0.25 USD/100万RRU | 1.25 USD/100万WRU | トラフィック予測不可 |
| Provisioned | 0.00065 USD/RCU/時間 | 0.00065 USD/WCU/時間 | 安定的トラフィック |
| Reserved | 最大77%割引 | 最大77%割引 | 1年/3年コミット |
8. Cassandra / ScyllaDB — 大規模書き込みの王
Cassandraアーキテクチャ
┌────────┐ ┌────────┐ ┌────────┐
│ Node A │──│ Node B │──│ Node C │
│ Token: │ │ Token: │ │ Token: │
│ 0-33 │ │ 34-66 │ │ 67-100 │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└───────────┼───────────┘
Gossip Protocol
-- キースペース作成(レプリケーション戦略含む)
CREATE KEYSPACE ecommerce WITH replication = {
'class': 'NetworkTopologyStrategy',
'us-east': 3,
'ap-northeast': 3
};
-- テーブル作成(パーティションキー + クラスタリングキー)
CREATE TABLE ecommerce.user_activity (
user_id UUID,
activity_date DATE,
activity_time TIMESTAMP,
activity_type TEXT,
details MAP<TEXT, TEXT>,
PRIMARY KEY ((user_id, activity_date), activity_time)
) WITH CLUSTERING ORDER BY (activity_time DESC)
AND compaction = {'class': 'TimeWindowCompactionStrategy',
'compaction_window_size': 1,
'compaction_window_unit': 'DAYS'};
ScyllaDB — Cassandra互換高性能代替
| 比較項目 | Cassandra | ScyllaDB |
|---|---|---|
| 言語 | Java | C++(Seastar) |
| アーキテクチャ | スレッドベース | Shard-per-core |
| GC影響 | GCポーズあり | GCなし |
| 同一HW性能 | 基準 | 3-10倍 |
| Cassandra互換 | オリジナル | CQL互換 |
9. 性能ベンチマーク比較
YCSBベンチマーク(同一HW: 8 vCPU, 32GB RAM, NVMe SSD)
| 操作 | PostgreSQL | MySQL | MongoDB | Redis | DynamoDB | ScyllaDB |
|---|---|---|---|---|---|---|
| 読取遅延(p99) | 2.1ms | 1.8ms | 1.5ms | 0.3ms | 4.2ms | 0.9ms |
| 書込遅延(p99) | 3.5ms | 2.9ms | 2.1ms | 0.4ms | 5.8ms | 1.2ms |
| 読取TPS | 45K | 52K | 58K | 250K | 25K | 120K |
| 書込TPS | 28K | 35K | 42K | 200K | 20K | 85K |
| 混合(50/50)TPS | 35K | 42K | 48K | 220K | 22K | 100K |
注意:ベンチマーク結果はワークロードパターン、データサイズ、インデックス構成等により大きく異なります。
10. ユースケース別選択マトリックス
| ユースケース | 第1選択 | 第2選択 | 理由 |
|---|---|---|---|
| EC | PostgreSQL | MySQL | トランザクション + JSONB柔軟性 |
| SNS | MongoDB | Cassandra | 非構造化データ + 高書き込み |
| IoTセンサー | ScyllaDB | DynamoDB | 大容量時系列書き込み |
| リアルタイム分析 | PostgreSQL | ClickHouse | 複雑な集計クエリ |
| RAG/AI検索 | PostgreSQL(pgvector) | MongoDB(Atlas Vector) | ベクトル + 全文検索 |
| キャッシュ | Redis | DragonflyDB | 超低遅延、豊富なデータ構造 |
| セッションストア | Redis | DynamoDB | 高速読み書き、TTL |
| チャット | MongoDB | Cassandra | 柔軟なスキーマ、時間順ソート |
| ゲームランキング | Redis | DynamoDB | Sorted Set、高速更新 |
| ログ管理 | Elasticsearch | MongoDB | 全文検索、時系列 |
11. マルチDBアーキテクチャパターン
Polyglot Persistence(多言語永続化)
┌─────────────────────────────────────────────────┐
│ アプリケーション層 │
└───────┬──────────┬──────────┬──────────┬────────┘
│ │ │ │
┌────▼────┐ ┌──▼───┐ ┌───▼───┐ ┌───▼────┐
│PostgreSQL│ │Redis │ │MongoDB│ │Elastic │
│(注文/決済)│ │(Cache)│ │(商品) │ │(検索) │
└─────────┘ └──────┘ └───────┘ └────────┘
Cache-Asideパターン
import redis
import psycopg2
import json
r = redis.Redis(host='localhost', port=6379)
def get_product(product_id):
# 1. キャッシュ確認
cache_key = f"product:{product_id}"
cached = r.get(cache_key)
if cached:
return json.loads(cached)
# 2. キャッシュミス — DB照会
conn = psycopg2.connect("dbname=ecommerce")
cur = conn.cursor()
cur.execute("SELECT * FROM products WHERE id = %s", (product_id,))
product = cur.fetchone()
if product:
# 3. キャッシュに保存(TTL 1時間)
r.setex(cache_key, 3600, json.dumps(product))
return product
12. コスト比較(マネージドサービス)
月間コスト予想(中規模サービス:100GB、5000 TPS)
| サービス | プロバイダー | インスタンス | 月額コスト(USD) |
|---|---|---|---|
| RDS PostgreSQL | AWS | db.r6g.xlarge | ~350 |
| Cloud SQL PostgreSQL | GCP | db-custom-4-16384 | ~320 |
| RDS MySQL | AWS | db.r6g.xlarge | ~350 |
| Atlas MongoDB | MongoDB | M40 | ~480 |
| ElastiCache Redis | AWS | cache.r6g.xlarge | ~450 |
| DynamoDB On-Demand | AWS | - | ~180-600 |
| Neon PostgreSQL | Neon | Scale | ~69-189 |
| PlanetScale MySQL | PlanetScale | Scaler Pro | ~39-299 |
13. 面接質問20選
基本概念(1-5)
Q1: ACIDとBASEの違いを説明してください。
ACID(Atomicity, Consistency, Isolation, Durability):伝統的RDBMSのトランザクション属性。全ての操作が完全に成功するか完全に失敗し、データ一貫性を保証します。
BASE(Basically Available, Soft state, Eventually consistent):NoSQLのアプローチ。常に利用可能ですが、即時一貫性の代わりに結果整合性を保証します。
選択基準:金融/決済システムにはACID、SNSフィード/いいねカウンターにはBASEが適合します。
Q2: CAP定理を実務例と共に説明してください。
- CPシステム(MongoDB):ネットワーク分断発生時、一貫性のために一部ノードの可用性を犠牲。プライマリ選出中は書き込み不可。
- APシステム(Cassandra, DynamoDB):ネットワーク分断でも全ノードが応答するが、ノード間のデータが一時的に異なる可能性がある。
- CAシステム:ネットワーク分断がない単一ノードシステム。分散環境では事実上存在しない。
Q3: インデックスの種類と適切な使用例を説明してください。
- B-Treeインデックス: 範囲検索、ソートに最適。ほとんどのデフォルトインデックス。O(log N)
- Hashインデックス: 等値比較(=)のみ。O(1)
- GIN: 配列、JSONB、全文検索に適合
- GiST: 空間データ(PostGIS)、範囲型に適合
- BRIN: 物理的にソートされた大規模テーブル(時系列)に効果的
- Bloomインデックス: 多数のカラムに対する等値比較フィルタリング
Q4: N+1クエリ問題とは何で、どう解決しますか?
N+1問題:1回のクエリでN件の結果を取得した後、各結果に対して追加クエリをN回実行する非効率的なパターン。
解決方法:
- JOIN: リレーショナルDBで1回のクエリでデータを結合
- Eager Loading: ORMで関連データを事前ロード
- DataLoaderパターン: GraphQLでバッチリクエストにまとめて処理
- MongoDB: 埋め込みパターンで関連データを1つのドキュメントに格納
Q5: データベース正規化と非正規化のトレードオフを説明してください。
正規化(1NF-BCNF):
- メリット:データ重複最小化、一貫性維持が容易、ストレージ節約
- デメリット:JOIN増加で読み取り性能低下、複雑なクエリ
非正規化:
- メリット:読み取り性能向上(JOIN減少)、単純なクエリ
- デメリット:データ重複、更新異常リスク、ストレージ増加
実務ガイド:OLTPは3NF以上の正規化、OLAP/読み取り集中ワークロードは意図的な非正規化を検討。
深化問題(6-10)
Q6: PostgreSQLのMVCCとMySQL InnoDBのMVCCの違いは?
PostgreSQL MVCC:
- 各行の複数バージョンをテーブルに直接格納(xmin, xmax)
- 古いバージョンはVACUUMで整理
- メリット:読み取り時ロックなし、高い同時実行性
- デメリット:テーブル膨張(bloat)、VACUUMオーバーヘッド
MySQL InnoDB MVCC:
- Undo Logに以前のバージョンを格納
- 現在の行には常に最新バージョン
- Purgeスレッドが不要なUndoを整理
- メリット:テーブル膨張なし、シンプルな管理
- デメリット:Undoログ増大時の性能低下
Q7: シャーディング戦略の種類と選択基準は?
- ハッシュシャーディング: キーをハッシュして均等分散。範囲クエリが非効率的。
- 範囲シャーディング: キー範囲で分割。ホットスポットリスク。時系列に適合。
- 地理ベースシャーディング: ユーザー位置ベースの分割。地域別規制準拠に有用。
- ディレクトリベースシャーディング: マッピングテーブルで柔軟なルーティング。管理複雑度が高い。
シャードキー選択基準:高いカーディナリティ、均等分散、クエリパターンと一致。
Q8: Redisはシングルスレッドなのになぜ速いのですか?
- インメモリ処理: 全データがRAMにあるためディスクI/Oなし
- I/O多重化: epoll/kqueueで数千接続を単一スレッドで処理
- ロック不要: シングルスレッドのため同時実行制御オーバーヘッドなし
- 最適化されたデータ構造: SDS、ziplist、intset等のメモリ効率的な構造
- Redis 6.0+: I/Oスレッディング導入(コマンド処理は依然としてシングルスレッド)
Q9: MongoDBで埋め込みとリファレンスのどちらを選ぶべきですか?
埋め込み(サブドキュメント):
- 一緒に照会されるデータ
- 1:1または1:少数の関係
- 16MBドキュメントサイズ制限内
- 例:注文と注文アイテム、ユーザーと住所
リファレンス(別コレクション):
- 独立して照会/更新されるデータ
- 1:多数または多:多の関係
- ドキュメントサイズが急速に増加する場合
- 例:ブログ記事とコメント、商品とレビュー
Q10: コネクションプーリングが重要な理由と設定方法は?
DB接続作成コスト:TCPハンドシェイク + 認証 + セッション割り当てで数~数十ms必要。リクエスト毎に接続を作成すると性能が大きく低下します。
設定例(HikariCP):
maximumPoolSize: 一般的にCPUコア数 x 2 + ディスク数minimumIdle: 最小アイドル接続数connectionTimeout: プールから接続を待つ最大時間idleTimeout: アイドル接続維持時間
PostgreSQLはプロセスベースなので、PgBouncerを前に置いてコネクションプーリングを管理するのがベストプラクティスです。
実践/システム設計(11-15)
Q11: 大規模トラフィックECサービスのDBアーキテクチャを設計してください。
- 商品カタログ: MongoDB(柔軟な属性、高速読み取り)
- 注文/決済: PostgreSQL(ACIDトランザクション)
- カート/セッション: Redis(TTL、高速読み書き)
- 商品検索: Elasticsearch(全文検索、ファセット)
- レコメンドシステム: PostgreSQL pgvector(ベクトル類似度)
- 分析/レポート: ClickHouseまたはBigQuery
Q12: データベースマイグレーション戦略を説明してください。
- Dual-Writeパターン: 両方のDBに同時書き込み、段階的に読み取りを切り替え
- CDC(Change Data Capture): Debezium等でリアルタイムデータ同期
- Shadow Traffic: 新DBにトラフィックをミラーリングして性能検証
- Blue-Green: 2つの環境を準備して一度に切り替え
Q13: レプリケーション遅延問題をどう解決しますか?
- Read-your-writes一貫性: 書き込み後、短時間はマスターから読み取り
- 最小レプリケーション確認: PostgreSQLの
synchronous_commit設定 - 遅延モニタリング:
pg_stat_replicationのreplay_lagチェック - GTIDベースルーティング: MySQL GTIDで特定時点まで反映されたレプリカにルーティング
- キャッシュ活用: 書き込み直後にキャッシュに最新値を保存
Q14: 大規模テーブルでスキーマ変更を安全に実行するには?
PostgreSQL:
ALTER TABLE ADD COLUMN(DEFAULT無し):即時完了CREATE INDEX CONCURRENTLY:テーブルロックなしでインデックス作成
MySQL:
pt-online-schema-change(Percona):トリガーベースのオンライン変更gh-ost(GitHub):バイナリログベースのオンライン変更- MySQL 8.0+
INSTANTDDL:メタデータのみの変更操作
MongoDB:
- スキーマレスなのでほとんどのマイグレーション不要
Q15: DB性能モニタリングで最も重要な指標は?
- クエリ性能: スロークエリログ、p95/p99レスポンスタイム
- 接続数: アクティブ/アイドル接続、コネクションプール使用率
- キャッシュヒット率: Buffer Pool/Shared Bufferヒット率(目標:99%以上)
- レプリケーション遅延: マスター/レプリカ間の遅延時間
- ディスクI/O: IOPS、レイテンシ、使用率
- ロック待機: 行ロック/テーブルロック待機時間と頻度
- トランザクションスループット: TPS、コミット/ロールバック比率
深化実践問題(16-20)
Q16: Hot Partition問題とは何で、どう解決しますか?
特定のパーティション/シャードにトラフィックが集中し、性能ボトルネックが発生する問題です。
解決方法:
- Write Sharding: キーにランダムサフィックス追加
- Composite Key: 日付/時間等をキーに含めて分散
- キャッシュレイヤー: 読み取りホットスポットをRedisで吸収
- 分散カウンター: 1つのカウンターをN個に分割して合算
Q17: バックアップ戦略の種類とRPO/RTOを説明してください。
- RPO(Recovery Point Objective): 許容可能な最大データ損失時間
- RTO(Recovery Time Objective): 許容可能な最大復旧時間
バックアップ種類:
- フルバックアップ: 全データ。RTO短い、ストレージ大きい
- 増分バックアップ: 前回以降の変更分。ストレージ少ない、復旧複雑
- 継続的アーカイビング(WAL): PITR可能。RPOほぼゼロ
- スナップショット: EBSスナップショット、RDS自動バックアップ
Q18: スロークエリの分析と最適化プロセスは?
- 識別: スロークエリログ有効化
- 分析: EXPLAIN ANALYZEで実行計画確認
- 最適化順序:
- インデックス追加/改善
- クエリリファクタリング
- パーティショニング適用
- データアーカイビング
- 非正規化検討
- 検証: 変更前後の性能比較
- モニタリング: 継続的な観察
Q19: Eventually Consistentシステムでデータ整合性をどう保証しますか?
- Read Repair: 読み取り時に不整合を発見したら最新値で修正
- Anti-Entropy(Merkle Tree): バックグラウンドでノード間データ比較/修正
- Conflict Resolution: LWW、ベクタークロック、カスタムマージロジック
- Quorum読み書き: R + W > N条件で強い一貫性確保
- Sagaパターン: 分散トランザクションの代わりに補償トランザクションで一貫性維持
Q20: 2025年のDB選定で最も重要な要素3つは?
-
AI/ベクトル検索サポート: RAGパイプラインが標準になり、ベクトル検索機能が必須。pgvector、Atlas Vector Search、Redis Vector Searchから選択。
-
運用複雑度 vs コスト: マネージドサービスの利便性 vs セルフホスティングのコスト削減。チーム規模とDevOps能力に基づいて決定。
-
データ局所性と規制: GDPR、各国の個人情報保護法等のデータ主権規制。DynamoDB Global Tables、CockroachDBの地域ベース分散が解決策になりうる。
14. クイズ
クイズ1: PostgreSQLでJSONBとJSON型の主な違い2つは?
- 格納方式: JSONはテキストのまま格納、JSONBはバイナリに分解して格納。JSONBは書き込みが若干遅いが、読み取り/検索が遥かに速い。
- インデックス: JSONBはGINインデックスをサポートし、キー/値検索がO(log N)。JSONはインデックス不可能。
クイズ2: RedisのSorted Setが内部で使用するデータ構造は?
Skip List + Hash Tableの組み合わせです。
- Skip List: ソートされた順序で範囲検索 O(log N)
- Hash Table: スコア参照 O(1)
要素が128個以下で値が64バイト以下の場合、ziplist(7.0+ではlistpack)を使用してメモリを節約します。
クイズ3: DynamoDBでGSIとLSIの違いは?
| 項目 | GSI | LSI |
|---|---|---|
| パーティションキー | テーブルと異なる可能 | テーブルと同一 |
| ソートキー | 自由に選択 | 自由に選択 |
| 容量制限 | なし | パーティション当たり10GB |
| 作成タイミング | テーブル作成後も可能 | テーブル作成時のみ |
| 一貫性 | 結果整合性のみ | 強い一貫性も可能 |
実務ヒント:ほとんどの場合GSIが柔軟なので、GSIを優先使用します。
クイズ4: MongoDBでトランザクションを使うべき時と避けるべき時は?
使うべき時:
- 複数ドキュメント/コレクションにまたがる原子的更新
- データ一貫性がビジネス的に必須
避けるべき時:
- 単一ドキュメント更新(MongoDBは単一ドキュメントレベルで既に原子的)
- 高スループットが必要な操作
- シャード環境での頻繁なマルチシャードトランザクション
クイズ5: VACUUMがPostgreSQLで重要な理由は?
PostgreSQLのMVCCは更新/削除時に以前のバージョンを即座に削除しません。VACUUMはこの「デッドタプル」を整理します。
行わないと:
- テーブル膨張: ディスク空間の浪費、シーケンシャルスキャン性能低下
- インデックス膨張: インデックスサイズ増加、検索性能低下
- トランザクションIDラップアラウンド: 約20億トランザクション後にデータ損失リスク
Autovacuumがデフォルトで有効ですが、書き込み負荷の高いテーブルはパラメータチューニングが必要です。
参考資料
- PostgreSQL 17公式ドキュメント: https://www.postgresql.org/docs/17/
- MySQL 9.0公式ドキュメント: https://dev.mysql.com/doc/refman/9.0/en/
- MongoDB 8.0公式ドキュメント: https://www.mongodb.com/docs/manual/
- Redis公式ドキュメント: https://redis.io/docs/
- Valkeyプロジェクト: https://valkey.io/
- DynamoDB開発者ガイド: https://docs.aws.amazon.com/dynamodb/
- ScyllaDBドキュメント: https://opensource.docs.scylladb.com/
- DB-Enginesランキング: https://db-engines.com/en/ranking
- YCSBベンチマーク: https://github.com/brianfrankcooper/YCSB
- "Designing Data-Intensive Applications" — Martin Kleppmann
この記事で取り上げた8つのデータベースは、それぞれ固有の強みを持っています。「最高のデータベース」は存在せず、「最適なデータベース」のみが存在します。ワークロードパターン、スケーリング要件、チーム能力、コスト制約を総合的に考慮して選択してください。そして1つのデータベースに全てを任せようとせず、Polyglot Persistence戦略で各データベースの強みを組み合わせることが2025年のベストプラクティスです。