データベース設計パターン
約10分
データベースとは、データを永続的に保存・検索・更新するためのシステムです。「どのDBを選ぶか」はシステムの性能・信頼性・開発コストに直結します。AIシステムでは、ユーザー情報・会話履歴・ドキュメント埋め込みベクトル・セッションキャッシュなど、性質の異なるデータを扱うため、用途に応じた複数DBを組み合わせる設計が一般的です。
データベースの種類
Section titled “データベースの種類”現代のシステム開発で使われるデータベースは6つの主要カテゴリに分類できます。
リレーショナルDB(SQL)
Section titled “リレーショナルDB(SQL)”リレーショナルデータベース(RDB)とは、データを行と列の表形式で管理し、SQL(Structured Query Language)でデータを操作するDBです。複数のテーブルを「外部キー」で結びつけ、JOIN操作でデータを結合できます。
特徴:
- ACID特性: Atomicity(原子性)・Consistency(一貫性)・Isolation(独立性)・Durability(永続性)を保証
- スキーマ(テーブル定義)が必須で、データ型・制約が厳密
- 複雑な結合クエリが得意
代表: PostgreSQL(オープンソースの最有力)、MySQL、Cloud SQL、Aurora
ドキュメントDB(NoSQL)
Section titled “ドキュメントDB(NoSQL)”ドキュメントデータベースとは、JSONのような柔軟な構造(ドキュメント)でデータを保存するNoSQLデータベースです。スキーマが固定されないため、フィールドが可変なデータを扱いやすいです。
{
"_id": "user_123",
"name": "田中太郎",
"preferences": {
"language": "ja",
"theme": "dark"
},
"tags": ["premium", "beta-tester"]
}代表: MongoDB、Firebase Firestore
キーバリューDB
Section titled “キーバリューDB”キーバリューデータベースとは、キー(名前)と値(データ)のシンプルなペアでデータを保存するDBです。構造は単純ですが、メモリ上で動作するため非常に高速です。
代表: Redis(最も広く使われる)、Memcached
ベクトルDB
Section titled “ベクトルDB”ベクトルデータベースとは、テキスト・画像・音声をAIモデルが数値化した「埋め込みベクトル」(浮動小数点数の配列)を保存し、意味的な類似度検索ができるDBです。RAG(Retrieval-Augmented Generation)の実装に不可欠です。
詳細は RAGとベクトルDB を参照してください。
代表: Pinecone、Weaviate、Chroma、pgvector(PostgreSQL拡張)
時系列データベースとは、タイムスタンプ付きのデータ(メトリクス、ログ、センサーデータ)の保存・集計に特化したDBです。
代表: InfluxDB、TimescaleDB(PostgreSQL拡張)
グラフデータベースとは、エンティティ(ノード)と関係(エッジ)でデータを表現するDBです。ソーシャルグラフ、知識グラフ、レコメンデーションエンジンに向きます。
代表: Neo4j
比較表: DBタイプの使い分け
Section titled “比較表: DBタイプの使い分け”| DBタイプ | 強み | 弱み | 典型的なユースケース | 代表DB |
|---|---|---|---|---|
| リレーショナル | ACID保証、複雑なJOIN | スキーマ変更コスト高 | ユーザー情報、注文、会話履歴 | PostgreSQL |
| ドキュメント | スキーマ柔軟、水平スケール容易 | JOINが苦手 | ユーザープロフィール、製品カタログ | MongoDB |
| キーバリュー | 超高速(マイクロ秒) | 複雑なクエリ不可 | セッション、キャッシュ、レート制限カウンター | Redis |
| ベクトル | 意味的類似検索 | 通常のCRUDは非効率 | 文書検索(RAG)、類似商品検索 | Pinecone, pgvector |
| 時系列 | 時系列集計が高速 | 汎用クエリは苦手 | メトリクス、ログ集計 | InfluxDB |
| グラフ | 関係性の横断検索 | 学習コスト高 | ソーシャルグラフ、推薦 | Neo4j |
AIシステムの典型的なデータアーキテクチャ
Section titled “AIシステムの典型的なデータアーキテクチャ”本番AIサービスでは複数のDBを組み合わせます。
graph TD
User["ユーザー"] --> App["アプリケーションサーバー\n(FastAPI / Node.js)"]
App --> PG["PostgreSQL\nユーザー情報\n会話履歴\nメタデータ"]
App --> Redis["Redis\nセッションキャッシュ\nレート制限カウンター\nLLMレスポンスキャッシュ"]
App --> VDB["ベクトルDB\nPinecone / pgvector\nドキュメント埋め込み"]
App --> Storage["オブジェクトストレージ\nS3 / GCS\n生ドキュメント\n添付ファイル"]
App --> LLMAPI["LLM API\nAnthropic / OpenAI"]
PG --> PGReplica["PostgreSQL\nレプリカ(読み取り専用)"]
Redis --> RedisSentinel["Redis Sentinel\n(高可用性)"]AIサービスのデータモデル例
Section titled “AIサービスのデータモデル例”PostgreSQL(メインDB):
-- ユーザーテーブル
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 会話テーブル
CREATE TABLE conversations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
title TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- メッセージテーブル
CREATE TABLE messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
conversation_id UUID NOT NULL REFERENCES conversations(id),
role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
content TEXT NOT NULL,
input_tokens INTEGER,
output_tokens INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);Redis(キャッシュ・セッション):
# セッション情報(TTL: 24時間)
SET session:abc123 '{"user_id":"uuid-xxx","plan":"pro"}' EX 86400
# レート制限カウンター(TTL: 60秒)
INCR ratelimit:user:uuid-xxx:2026050312
EXPIRE ratelimit:user:uuid-xxx:2026050312 60
# LLMレスポンスキャッシュ(同一プロンプトへの再利用)
SET cache:llm:sha256:... '{"content":"...","tokens":450}' EX 3600コネクションプーリング
Section titled “コネクションプーリング”コネクションプーリングとは、DBへの接続を事前に複数確立しておき、リクエストごとに接続を使い回す仕組みです。
PostgreSQLはデフォルトで最大100接続までですが、アプリケーションサーバーが多数起動すると接続数がすぐ上限に達します。PgBouncer というコネクションプーラーを挟むと、サーバー→PgBouncer間の多数の接続をPgBouncer→PostgreSQL間の少数の接続に集約できます。
アプリサーバー×10台(各10接続)= 100接続
↓ PgBouncer
PostgreSQL(20接続のみ)インデックスの基礎
Section titled “インデックスの基礎”インデックス(索引)とは、特定のカラムの値を高速に検索するためのデータ構造です。本の索引と同じ仕組みで、全行を走査(フルスキャン)せずに該当データを見つけられます。
-- user_idで会話を頻繁に検索するなら
CREATE INDEX idx_conversations_user_id ON conversations(user_id);
-- メールアドレスでユーザーを検索するなら(UNIQUE制約が自動でインデックスを作る)
CREATE UNIQUE INDEX idx_users_email ON users(email);インデックスは検索を速くしますが、INSERT/UPDATE時の更新コストが増えます。「頻繁に検索条件に使うカラム」に絞ってインデックスを作成します。
スキーママイグレーション
Section titled “スキーママイグレーション”スキーママイグレーションとは、本番DBのテーブル定義をアプリケーションのコード変更と合わせて安全に変更する仕組みです。
本番環境でのマイグレーション原則:
- 前方互換性を保つ: 新しいカラムは
NOT NULL DEFAULTなし(または既存データに矛盾しないデフォルト値あり)で追加 - 大きなテーブルへのALTERは注意: ロックが発生するためオフピーク時に実行
- ロールバック手順を用意: 失敗時にすぐ戻せる逆マイグレーションを事前に準備
代表ツール: Alembic(Python)、Flyway、Liquibase
バックアップとリカバリー
Section titled “バックアップとリカバリー”| 指標 | 意味 | 目安 |
|---|---|---|
| RTO(Recovery Time Objective) | 障害発生からシステム復旧までの許容時間 | 本番サービス: 1時間以内 |
| RPO(Recovery Point Objective) | 復旧時に許容できるデータの損失期間 | 重要データ: 1時間以内 |
マネージドDBサービス(AWS RDS、Cloud SQL、Supabase)では自動バックアップとポイントインタイムリカバリー(任意の時点に復元できる機能)が標準で提供されます。
- PostgreSQLは汎用性が高く、多くのAIサービスのメインDBとして機能する
- Redisはセッション・キャッシュ・レート制限カウンターに不可欠な超高速キーバリューDB
- ベクトルDBはRAGのセマンティック検索に必要(小規模なら pgvector で始めるのが手軽)
- 本番AIサービスは PostgreSQL + Redis + ベクトルDB + オブジェクトストレージの組み合わせが標準構成
- コネクションプーリング・インデックス・マイグレーション管理は本番運用の基礎
よくある質問
Section titled “よくある質問”Q: PostgreSQLですべてを賄えますか?
A: 多くのケースではPostgreSQLで十分です。pgvectorでベクトル検索、TimescaleDB拡張で時系列データも扱えます。Redis を使わずにPostgreSQLでセッション管理することも可能ですが、高頻度の読み書き(レート制限カウンターなど)はRedisのほうが性能が良く、接続数を節約できます。
Q: キャッシュを追加すべきタイミングはいつですか?
A: 「同じクエリが頻繁に発行される」「DBのレイテンシがボトルネックになっている」「LLM APIへの同一プロンプトが重複して送信されている」場合がキャッシュ追加の目安です。最初からRedisを入れると監視対象が増えるため、必要になってから追加するアプローチも有効です。
Q: MongoDBとPostgreSQLどちらを選ぶべきですか?
A: AIサービスの多くのユースケースではPostgreSQLが推奨されます。JSONBカラムで柔軟なスキーマも扱えるため、スキーマが可変なデータでもPostgreSQLで対応可能です。MongoDBはすでにチームに知見がある場合や、スキーマが非常に不定形なデータが中心の場合に選択肢となります。
Q: データが増えてきたらどうスケールしますか?
A: まず読み取りレプリカを追加して読み取り負荷を分散します。次に頻繁に使うデータをRedisでキャッシュします。さらに大きくなる場合はパーティショニング(テーブルを期間・ユーザーIDなどで分割)やシャーディングを検討します。多くのAIサービスはレプリカ+キャッシュの段階で十分です。
このページの外部仕様・背景情報は、参考文献を参照してください。[1][2][3][4][5]