コンテンツにスキップ
LinkedInX

データベース設計パターン

約10分

対象読者: AIシステムのデータ設計を学びたいエンジニア、DBの種類と使い分けを理解したい方
前提知識: クラウドアーキテクチャ入門の全体構成を把握していると理解が深まります

データベースとは、データを永続的に保存・検索・更新するためのシステムです。「どのDBを選ぶか」はシステムの性能・信頼性・開発コストに直結します。AIシステムでは、ユーザー情報・会話履歴・ドキュメント埋め込みベクトル・セッションキャッシュなど、性質の異なるデータを扱うため、用途に応じた複数DBを組み合わせる設計が一般的です。

現代のシステム開発で使われるデータベースは6つの主要カテゴリに分類できます。

リレーショナルデータベース(RDB)とは、データを行と列の表形式で管理し、SQL(Structured Query Language)でデータを操作するDBです。複数のテーブルを「外部キー」で結びつけ、JOIN操作でデータを結合できます。

特徴:

  • ACID特性: Atomicity(原子性)・Consistency(一貫性)・Isolation(独立性)・Durability(永続性)を保証
  • スキーマ(テーブル定義)が必須で、データ型・制約が厳密
  • 複雑な結合クエリが得意

代表: PostgreSQL(オープンソースの最有力)、MySQL、Cloud SQL、Aurora

ドキュメントデータベースとは、JSONのような柔軟な構造(ドキュメント)でデータを保存するNoSQLデータベースです。スキーマが固定されないため、フィールドが可変なデータを扱いやすいです。

{
  "_id": "user_123",
  "name": "田中太郎",
  "preferences": {
    "language": "ja",
    "theme": "dark"
  },
  "tags": ["premium", "beta-tester"]
}

代表: MongoDB、Firebase Firestore

キーバリューデータベースとは、キー(名前)と値(データ)のシンプルなペアでデータを保存するDBです。構造は単純ですが、メモリ上で動作するため非常に高速です。

代表: Redis(最も広く使われる)、Memcached

ベクトルデータベースとは、テキスト・画像・音声をAIモデルが数値化した「埋め込みベクトル」(浮動小数点数の配列)を保存し、意味的な類似度検索ができるDBです。RAG(Retrieval-Augmented Generation)の実装に不可欠です。

詳細は RAGとベクトルDB を参照してください。

代表: Pinecone、Weaviate、Chroma、pgvector(PostgreSQL拡張)

時系列データベースとは、タイムスタンプ付きのデータ(メトリクス、ログ、センサーデータ)の保存・集計に特化したDBです。

代表: InfluxDB、TimescaleDB(PostgreSQL拡張)

グラフデータベースとは、エンティティ(ノード)と関係(エッジ)でデータを表現するDBです。ソーシャルグラフ、知識グラフ、レコメンデーションエンジンに向きます。

代表: Neo4j

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(高可用性)"]

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

コネクションプーリングとは、DBへの接続を事前に複数確立しておき、リクエストごとに接続を使い回す仕組みです。

PostgreSQLはデフォルトで最大100接続までですが、アプリケーションサーバーが多数起動すると接続数がすぐ上限に達します。PgBouncer というコネクションプーラーを挟むと、サーバー→PgBouncer間の多数の接続をPgBouncer→PostgreSQL間の少数の接続に集約できます。

アプリサーバー×10台(各10接続)= 100接続
      ↓ PgBouncer
PostgreSQL(20接続のみ)

インデックス(索引)とは、特定のカラムの値を高速に検索するためのデータ構造です。本の索引と同じ仕組みで、全行を走査(フルスキャン)せずに該当データを見つけられます。

-- user_idで会話を頻繁に検索するなら
CREATE INDEX idx_conversations_user_id ON conversations(user_id);

-- メールアドレスでユーザーを検索するなら(UNIQUE制約が自動でインデックスを作る)
CREATE UNIQUE INDEX idx_users_email ON users(email);

インデックスは検索を速くしますが、INSERT/UPDATE時の更新コストが増えます。「頻繁に検索条件に使うカラム」に絞ってインデックスを作成します。

スキーママイグレーションとは、本番DBのテーブル定義をアプリケーションのコード変更と合わせて安全に変更する仕組みです。

本番環境でのマイグレーション原則:

  1. 前方互換性を保つ: 新しいカラムは NOT NULL DEFAULT なし(または既存データに矛盾しないデフォルト値あり)で追加
  2. 大きなテーブルへのALTERは注意: ロックが発生するためオフピーク時に実行
  3. ロールバック手順を用意: 失敗時にすぐ戻せる逆マイグレーションを事前に準備

代表ツール: Alembic(Python)、Flyway、Liquibase

指標意味目安
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 + オブジェクトストレージの組み合わせが標準構成
  • コネクションプーリング・インデックス・マイグレーション管理は本番運用の基礎

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]

  1. PostgreSQL Documentation
  2. Redis Documentation
  3. Pinecone Documentation
  4. pgvector GitHub
  5. PgBouncer Documentation
クイズ