この記事は、AIアプリでPostgreSQLとClickHouseをどう分けるかを考えるメモです。Postgresを捨てる話ではありません。Postgresで足りるところを残し、重くなる分析をClickHouseに逃がす話です。記述は2026年6月9日時点の公式情報をもとにしています。
はじめに
AIアプリを作ると、最初はPostgreSQLで足ります。
ユーザー、ログイン、権限、課金、設定、会話履歴。全部Postgresに置けるし、実際それで始めるのが自然です。
でも、あとから分析したくなるものが増えます。
- モデル別のレイテンシ
- 日次のトークン消費
- RAG検索の失敗傾向
- tool callのエラー率
- 顧客ごとの利用量
- プロンプト変更前後の品質
このあたりを全部Postgresに背負わせると、アプリ本体のDBがログ分析基盤になってしまいます。
この記事では、AIアプリのDBを「Postgresで足りるところ」と「ClickHouseに逃がすところ」に分けます。
先に結論
自分なら、こう分けます。
| データ | 置き場所 | 理由 |
|---|---|---|
| ユーザー | PostgreSQL | 更新と整合性が大事 |
| 権限 | PostgreSQL | 判定に遅延を入れたくない |
| 課金 | PostgreSQL | トランザクションが大事 |
| アプリ設定 | PostgreSQL | 参照と更新が混ざる |
| 会話の最終結果 | PostgreSQLまたはオブジェクトストレージ | プロダクト要件次第 |
| LLM実行ログ | ClickHouse | 量が増えて集計したくなる |
| RAG検索ログ | ClickHouse | 検索品質の分析に使う |
| tool callログ | ClickHouse | エラー率と遅延を見たい |
| 監査ログ | ClickHouse | あとから期間集計したい |
| ダッシュボード用集計 | ClickHouse | 本番DBから切り離したい |
Postgresは正規データ。
ClickHouseはログと分析。
この線を引くと、設計が楽になります。
Postgresで足りるところ
ユーザーと権限
ユーザー、組織、ロール、権限はPostgresに置きます。
権限判定はアプリの安全に関わります。分析用DBに置いて遅延や同期ズレを許すより、正規データとして扱うほうが自然です。
課金と注文
課金や注文もPostgresです。
決済状態、請求、プラン変更、利用上限。ここはトランザクションが大事です。PostgreSQLのドキュメントでは、トランザクションは複数の処理をまとめて、全部成功するか全部なかったことにする仕組みだと説明されています。1 ログ分析の都合でClickHouseに寄せる場所ではありません。
アプリ設定
モデルの選択、プロンプトテンプレート、組織ごとの設定もPostgresに置きます。
設定は更新されます。参照もされます。管理画面から変更されます。この手のデータはPostgresが扱いやすいです。
小さなログ
初期の小さなログならPostgresで十分です。
最初からClickHouseを入れると、運用するDBが増えます。小さい段階では、分析より開発速度を優先したほうがよいこともあります。
pgvectorで足りるRAG
小さなRAGなら、Postgresとpgvectorで足ります。
pgvectorはPostgresでベクトルを保存し、HNSWやIVFFlatのインデックスを使えます。2 文書、メタデータ、embeddingを同じDBに置けるので、小さく始めるには便利です。
ClickHouseに逃がすところ
LLM実行ログ
LLM実行ログはClickHouseに逃がしやすいです。
モデル、トークン数、レイテンシ、ステータス、コスト。これらはあとから期間やモデルで集計したくなります。ログが増えるほど、列指向DBのほうが合います。
RAG検索ログ
RAG検索ログもClickHouse向きです。
どの文書が検索されたか。何位だったか。スコアはいくつだったか。回答に使われたか。ユーザー評価はどうだったか。
このログを残すと、RAGの失敗原因を見やすくなります。
tool callログ
AIエージェントでは、tool callのログが増えます。
どのツールを呼んだか、引数は何だったか、成功したか、何ミリ秒かかったか。これを集計すると、遅いツールや失敗しやすいツールが見えます。
顧客向けダッシュボード
顧客向けの分析画面はClickHouseへ逃がしたいです。
ダッシュボードは同じような集計を何度も投げます。複数ユーザーが同時に開きます。本番Postgresに直接当てるより、分析用のClickHouseに逃がすほうが安心です。
長期保存ログ
LLMの品質改善では、過去ログを見返したくなります。
30日では足りない。90日でも足りない。モデル変更やプロンプト変更の影響を見るなら、半年や1年の集計が欲しくなることもあります。
Postgres本体に長期ログを抱えるより、ClickHouse側で保存期間を設計したほうが扱いやすいです。
どちらにも置かないほうがいいもの
ログ設計で怖いのは、残しすぎることです。
次のものは、そもそも保存しないか、保存前に削ります。
| データ | 理由 |
|---|---|
| APIキー | 漏れたときの被害が大きい |
| アクセストークン | ログに残す必要がない |
| 生の個人情報 | 分析にはID化で足りることが多い |
| プロンプト全文 | 機密情報が混ざることがある |
| 外部APIの生レスポンス | 必要なキーだけ抽出したほうがよい |
「あとで分析するかも」で全部残すと、あとで消すのが大変です。
どう連携するか
連携方法は大きく3つあります。
| 方法 | 向いている場面 |
|---|---|
| アプリからClickHouseへ直接INSERT | LLMログやイベントログ |
| PostgresからCDCで流す | 注文やユーザーデータを分析にも使いたい |
| バッチで同期 | 日次集計で足りる |
LLMログは、最初からClickHouseへ直接入れるのが分かりやすいです。
一方で、ユーザーや注文のようなPostgres上の正規データを分析に使いたいなら、CDCやバッチを考えます。ClickHouse Cloudでは、ClickPipesのPostgres CDC connectorがGAになっています。3
CDCは便利ですが、同期ズレがなくなるわけではありません。削除、更新、スキーマ変更、再同期、遅延をどう扱うかは先に決める必要があります。
最初のテーブル例
AIアプリのLLMログなら、最初はこれくらいでよいと思います。
CREATE TABLE llm_request_logs
(
event_time DateTime64(3),
tenant_id UInt32,
user_id UInt32,
request_id UUID,
model LowCardinality(String),
route LowCardinality(String),
status LowCardinality(String),
latency_ms UInt32,
input_tokens UInt32,
output_tokens UInt32,
cost_usd Decimal(12, 6)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(event_time)
ORDER BY (event_time, tenant_id, model, route);
ClickHouseの MergeTree では、ORDER BY がデータの並びに効きます。ClickHouseの解説では、part内の行が ORDER BY キーで並び、主キーインデックスは一定粒度ごとの値を持つスパースな形になると説明されています。4 クエリでよく使う条件に合わせて決めます。
この例では、期間で絞り、テナントやモデルで見る前提にしています。
よく見る集計
たとえば、モデル別のp95レイテンシを見ます。
SELECT
model,
count() AS requests,
quantile(0.95)(latency_ms) AS p95_latency_ms,
avg(latency_ms) AS avg_latency_ms
FROM llm_request_logs
WHERE event_time >= now() - INTERVAL 7 DAY
GROUP BY model
ORDER BY requests DESC;
quantile は近似値を返す集計関数です。傾向を見るダッシュボードでは使いやすいですが、厳密な値が必要なら quantileExact などを検討します。5
日次コストも見ます。
SELECT
toDate(event_time) AS date,
model,
sum(input_tokens) AS input_tokens,
sum(output_tokens) AS output_tokens,
sum(cost_usd) AS cost_usd
FROM llm_request_logs
WHERE event_time >= now() - INTERVAL 30 DAY
GROUP BY date, model
ORDER BY date, model;
こういう集計を本番PostgresではなくClickHouseへ逃がしたい。
それがこの記事の主張です。
小さく始める手順
いきなり全部を分ける必要はありません。
- まずPostgresでアプリを作る
- LLMログだけClickHouseへ直接入れる
- ダッシュボードをClickHouseから読む
- 必要になったらPostgresの一部データをCDCやバッチで流す
- よく見る集計をmaterialized viewにする
これくらいが始めやすいです。
まとめ
AIアプリのDB設計は、PostgresかClickHouseかの二択ではありません。
Postgresで足りるところはPostgresでいい。ユーザー、権限、課金、設定。ここを無理に動かす必要はありません。
ClickHouseに逃がしたいのは、増え続けるログと重い分析です。
LLM実行ログ、RAG検索ログ、tool callログ、日次集計、顧客向けダッシュボード。
この分担にすると、Postgresを守りながら分析を強くできます。