メインコンテンツへスキップ

概要

Shannonは、永続的なストレージのためにPostgreSQLとpgvector拡張を使用しています。データベースは2つのスキーマに整理されています:
  • auth - 認証、マルチテナンシー、およびセキュリティ
  • public - コアアプリケーションテーブル(タスク、エージェント、セッション)
テーブル数: 18テーブル
拡張機能: uuid-ossp, pg_trgm, btree_gin, pgcrypto

エンティティリレーションシップ図

┌─────────────────┐
│  auth.tenants   │
└────────┬────────┘

         │ 1:N

┌─────────────────┐        ┌──────────────────┐
│   auth.users    │◄───────│  auth.api_keys   │
└────────┬────────┘   N:1  └──────────────────┘

         │ 1:N

┌─────────────────┐        ┌──────────────────┐
│   public.users  │◄───────│   sessions       │
└────────┬────────┘   1:N  └──────────────────┘

         │ 1:N

┌──────────────────────────┐
│   task_executions        │
│  (workflow_id = PK)      │
└──────────┬───────────────┘

           │ 1:N

┌──────────────────────────┐        ┌──────────────────┐
│   agent_executions       │◄───────│  tool_executions │
└──────────┬───────────────┘   1:N  └──────────────────┘

           │ 1:N

┌──────────────────────────┐
│     tool_calls           │
└──────────────────────────┘

┌──────────────────────────┐        ┌──────────────────┐
│   event_logs             │        │  token_usage     │
│  (workflow_id)           │        └──────────────────┘
└──────────────────────────┘

┌──────────────────────────┐        ┌───────────────────┐
│  usage_daily_aggregates  │        │  learning_cases   │
└──────────────────────────┘        └───────────────────┘

スキーマ: auth (認証とマルチテナンシー)

auth.tenants

目的: マルチテナントの組織管理
カラム制約説明
idUUIDPK, DEFAULT gen_random_uuid()テナント識別子
nameVARCHAR(255)NOT NULL組織名
slugVARCHAR(100)UNIQUE, NOT NULLURLセーフ識別子
planVARCHAR(50)DEFAULT ‘free’サブスクリプションプラン(free, pro, enterprise)
token_limitINTEGERDEFAULT 10000月間トークン許容量
monthly_token_usageINTEGERDEFAULT 0現在の月の使用量
rate_limit_per_hourINTEGERDEFAULT 1000APIレート制限
is_activeBOOLEANDEFAULT trueテナントのステータス
created_atTIMESTAMPDEFAULT NOW()作成時間
updated_atTIMESTAMPDEFAULT NOW()最終更新時間
metadataJSONBDEFAULT ''追加のテナントデータ
インデックス:
  • slugに対する主キー(UNIQUE)
:
-- アクティブなテナントを取得
SELECT id, name, plan, token_limit
FROM auth.tenants
WHERE is_active = true;

-- トークン使用量を確認
SELECT name, monthly_token_usage, token_limit,
       (monthly_token_usage::FLOAT / token_limit * 100) as usage_percentage
FROM auth.tenants
WHERE monthly_token_usage > token_limit * 0.8;

auth.users

目的: ユーザー認証とプロフィール管理
カラム制約説明
idUUIDPK, DEFAULT gen_random_uuid()ユーザー識別子
emailVARCHAR(255)UNIQUE, NOT NULLユーザーのメール
usernameVARCHAR(100)UNIQUE, NOT NULLユーザー名
password_hashVARCHAR(255)NOT NULLBcryptパスワードハッシュ
full_nameVARCHAR(255)フルネーム
tenant_idUUIDFK → auth.tenants, NOT NULL組織
roleVARCHAR(50)DEFAULT ‘user’役割(user, admin, owner)
is_activeBOOLEANDEFAULT trueアカウントのステータス
is_verifiedBOOLEANDEFAULT falseメール確認
email_verified_atTIMESTAMP確認タイムスタンプ
created_atTIMESTAMPDEFAULT NOW()アカウント作成
updated_atTIMESTAMPDEFAULT NOW()最終更新
last_loginTIMESTAMP最終ログイン時間
metadataJSONBDEFAULT ''追加のユーザーデータ
インデックス:
  • idx_users_email ON (email)
  • idx_users_username ON (username)
  • idx_users_tenant_id ON (tenant_id)
:
-- テナント内のすべてのユーザーを取得
SELECT u.email, u.username, u.role, u.last_login
FROM auth.users u
WHERE u.tenant_id = '...'
  AND u.is_active = true
ORDER BY u.last_login DESC NULLS LAST;

-- 非アクティブなユーザーを見つける
SELECT email, created_at, last_login
FROM auth.users
WHERE last_login < NOW() - INTERVAL '90 days'
   OR last_login IS NULL;

auth.api_keys

目的: プログラムによるアクセスのためのAPIキー管理
カラム制約説明
idUUIDPK, DEFAULT gen_random_uuid()キー識別子
key_hashVARCHAR(255)UNIQUE, NOT NULLキーのSHA256ハッシュ
key_prefixVARCHAR(20)NOT NULL最初の8文字(表示用)
user_idUUIDFK → auth.usersキーの所有者
tenant_idUUIDFK → auth.tenants, NOT NULL組織
nameVARCHAR(100)NOT NULLキー名/説明
descriptionTEXT詳細な説明
scopesTEXT[]DEFAULT […]権限配列
rate_limit_per_hourINTEGERDEFAULT 1000キー固有のレート制限
last_usedTIMESTAMP最終使用タイムスタンプ
expires_atTIMESTAMP有効期限
is_activeBOOLEANDEFAULT trueキーステータス
created_atTIMESTAMPDEFAULT NOW()作成時間
metadataJSONBDEFAULT ''追加のキーデータ
インデックス:
  • idx_api_keys_tenant_id ON (tenant_id)
  • idx_api_keys_key_prefix ON (key_prefix)
デフォルトスコープ:
  • tasks:run: タスク実行を許可
  • tasks:read: タスクのステータスと結果の読み取りを許可
  • sessions:manage: セッションの管理を許可
:
-- アクティブなAPIキーのリスト
SELECT key_prefix, name, last_used, expires_at
FROM auth.api_keys
WHERE is_active = true
  AND (expires_at IS NULL OR expires_at > NOW())
ORDER BY last_used DESC NULLS LAST;

-- 未使用のキーを見つける
SELECT key_prefix, name, created_at, last_used
FROM auth.api_keys
WHERE last_used IS NULL
  AND created_at < NOW() - INTERVAL '30 days';

-- 期限切れのキーを確認
SELECT key_prefix, name, expires_at
FROM auth.api_keys
WHERE expires_at BETWEEN NOW() AND NOW() + INTERVAL '7 days'
  AND is_active = true;

auth.refresh_tokens

目的: JWTリフレッシュトークンの保存と取り消し
カラム制約説明
idUUIDPK, DEFAULT gen_random_uuid()トークン識別子
token_hashVARCHAR(255)UNIQUE, NOT NULLSHA256ハッシュ
user_idUUIDFK → auth.usersトークン所有者
tenant_idUUIDFK → auth.tenants, NOT NULL組織
expires_atTIMESTAMPNOT NULL有効期限
revokedBOOLEANDEFAULT false取り消しステータス
revoked_atTIMESTAMP取り消し時間
ip_addressINETクライアントIP
user_agentTEXTクライアントユーザーエージェント
created_atTIMESTAMPDEFAULT NOW()作成時間
インデックス:
  • idx_refresh_tokens_user_id ON (user_id)
  • idx_refresh_tokens_token_hash ON (token_hash)
:
-- ユーザーのすべてのトークンを取り消す
UPDATE auth.refresh_tokens
SET revoked = true, revoked_at = NOW()
WHERE user_id = '...'
  AND revoked = false;

-- 期限切れのトークンをクリーンアップ
DELETE FROM auth.refresh_tokens
WHERE expires_at < NOW() - INTERVAL '7 days';

auth.audit_logs

目的: セキュリティイベントの監査トレイル
カラム制約説明
idUUIDPK, DEFAULT gen_random_uuid()ログエントリID
event_typeVARCHAR(100)NOT NULLイベントタイプ
user_idUUIDFK → auth.usersユーザー(nullable)
tenant_idUUIDFK → auth.tenantsテナント(nullable)
ip_addressINETクライアントIP
user_agentTEXTクライアントユーザーエージェント
detailsJSONBDEFAULT ''イベント詳細
created_atTIMESTAMPDEFAULT NOW()イベント時間
インデックス:
  • idx_audit_logs_user_id ON (user_id)
  • idx_audit_logs_tenant_id ON (tenant_id)
  • idx_audit_logs_event_type ON (event_type)
  • idx_audit_logs_created_at ON (created_at)
イベントタイプ:
  • login - ユーザーログイン
  • logout - ユーザーログアウト
  • api_key_created - APIキー生成
  • permission_changed - ロール/権限の変更
:
-- 最近のセキュリティイベント
SELECT event_type, user_id, ip_address, created_at
FROM auth.audit_logs
WHERE created_at > NOW() - INTERVAL '24 hours'
ORDER BY created_at DESC
LIMIT 100;

-- 失敗したログイン試行
SELECT user_id, ip_address, COUNT(*) as attempts
FROM auth.audit_logs
WHERE event_type = 'login_failed'
  AND created_at > NOW() - INTERVAL '1 hour'
GROUP BY user_id, ip_address
HAVING COUNT(*) > 5;

スキーマ: public (コアアプリケーション)

users

目的: アプリケーションユーザープロファイル(レガシー、auth.usersにリンク)
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()ユーザー識別子
external_idVARCHAR(255)UNIQUE, NOT NULL外部システムID
emailVARCHAR(255)メールアドレス
tenant_idUUIDテナント参照
metadataJSONBDEFAULT ''ユーザーメタデータ
created_atTIMESTAMPTZDEFAULT NOW()作成時間
updated_atTIMESTAMPTZDEFAULT NOW()最終更新
インデックス:
  • idx_users_tenant_id ON (tenant_id)
  • idx_users_external_id ON (external_id)
注意: このテーブルは後方互換性のために存在します。新しいコードはauth.usersを使用するべきです。

sessions

目的: ユーザーセッション管理とコンテキスト
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()セッション識別子
user_idUUIDFK → usersセッション所有者
tenant_idUUIDテナント参照
contextJSONBDEFAULT ''セッションコンテキストデータ
token_budgetINTEGERDEFAULT 10000トークン割り当て
tokens_usedINTEGERDEFAULT 0消費トークン
created_atTIMESTAMPTZDEFAULT NOW()セッション開始
updated_atTIMESTAMPTZDEFAULT NOW()最終活動
expires_atTIMESTAMPTZ有効期限
deleted_atTIMESTAMPTZDEFAULT NULLソフト削除のタイムスタンプ
deleted_byUUIDDEFAULT NULLセッションを削除したユーザー
インデックス:
  • idx_sessions_user_id ON (user_id)
  • idx_sessions_tenant_id ON (tenant_id)
  • idx_sessions_expires_at ON (expires_at)
  • idx_sessions_external_id ON ((context->>‘external_id’)) WHERE context->>‘external_id’ IS NOT NULL
  • idx_sessions_user_external_id UNIQUE ON (user_id, (context->>‘external_id’)) WHERE context->>‘external_id’ IS NOT NULL AND deleted_at IS NULL
  • idx_sessions_not_deleted ON (id) WHERE deleted_at IS NULL
  • idx_sessions_deleted_at ON (deleted_at) WHERE deleted_at IS NOT NULL
注意:
  • 外部ID(非UUIDセッションID)はcontext->>'external_id'に保存され、二重IDの検索を可能にします。
  • deleted_atカラムによるソフト削除のサポート - deleted_atがNULLでないセッションは削除されたと見なされます。
:
-- アクティブなセッション
SELECT id, user_id, tokens_used, token_budget, created_at
FROM sessions
WHERE expires_at > NOW()
  OR expires_at IS NULL
ORDER BY created_at DESC;

-- セッショントークンの使用状況
SELECT
    COUNT(*) as session_count,
    AVG(tokens_used) as avg_tokens,
    SUM(tokens_used) as total_tokens
FROM sessions
WHERE created_at > NOW() - INTERVAL '24 hours';

task_executions

目的: タスク/ワークフローの実行履歴とメトリクス
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()タスク識別子
workflow_idVARCHAR(255)UNIQUE, NOT NULLTemporal ワークフロー ID
user_idUUIDFK → usersタスク作成者
tenant_idUUIDテナント参照
session_idVARCHAR(255)セッション識別子
queryTEXTNOT NULLタスククエリ/プロンプト
modeVARCHAR(50)実行モード (SIMPLE, STANDARD, COMPLEX)
statusVARCHAR(50)NOT NULLタスクのステータス
started_atTIMESTAMPTZNOT NULL, DEFAULT NOW()開始時間
completed_atTIMESTAMPTZ完了時間
resultTEXT最終結果
responseJSONBDEFAULT ''構造化されたレスポンス
error_messageTEXTエラー詳細
total_tokensINTEGERDEFAULT 0使用トークン総数
prompt_tokensINTEGERDEFAULT 0入力トークン
completion_tokensINTEGERDEFAULT 0出力トークン
total_cost_usdDECIMAL(10,6)DEFAULT 0総コスト
duration_msINTEGER実行時間 (ms)
agents_usedINTEGERDEFAULT 0使用されたエージェント数
tools_invokedINTEGERDEFAULT 0ツール呼び出し数
cache_hitsINTEGERDEFAULT 0キャッシュヒット数
complexity_scoreDECIMAL(3,2)複雑さ (0.0-1.0)
metadataJSONB追加メタデータ
created_atTIMESTAMPTZDEFAULT NOW()レコード作成
インデックス:
  • idx_task_user_session ON (user_id, session_id)
  • idx_task_created_at ON (created_at DESC)
  • idx_task_status ON (status)
  • idx_task_workflow_id ON (workflow_id)
  • idx_task_executions_tenant_id ON (tenant_id)
  • idx_task_executions_session_id ON (session_id)
ステータス値:
  • RUNNING - タスク進行中
  • COMPLETED - タスクが正常に完了
  • FAILED - タスクがエラーで失敗
  • CANCELLED - ユーザーによってタスクがキャンセル
:
-- ユーザーの最近のタスク
SELECT workflow_id, query, status, duration_ms, total_cost_usd
FROM task_executions
WHERE user_id = '...'
ORDER BY started_at DESC
LIMIT 20;

-- 失敗したタスクの分析
SELECT
    DATE(started_at) as date,
    COUNT(*) as failed_count,
    AVG(duration_ms) as avg_duration
FROM task_executions
WHERE status = 'FAILED'
  AND started_at > NOW() - INTERVAL '7 days'
GROUP BY DATE(started_at)
ORDER BY date DESC;

-- コスト分析
SELECT
    user_id,
    COUNT(*) as task_count,
    SUM(total_cost_usd) as total_cost,
    AVG(total_cost_usd) as avg_cost,
    SUM(total_tokens) as total_tokens
FROM task_executions
WHERE started_at > NOW() - INTERVAL '30 days'
GROUP BY user_id
ORDER BY total_cost DESC;

agent_executions

目的: タスク内の個々のエージェント実行の詳細
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()実行 ID
task_execution_idUUIDFK → task_executions親タスク
agent_idVARCHAR(255)NOT NULLエージェント識別子
execution_orderINTEGERNOT NULL実行順序
inputTEXTNOT NULLエージェント入力
outputTEXTエージェント出力
modeVARCHAR(50)実行モード
stateVARCHAR(50)FSM ステート
tokens_usedINTEGERDEFAULT 0消費トークン
cost_usdDECIMAL(10,6)DEFAULT 0実行コスト
model_usedVARCHAR(100)LLM モデル
duration_msINTEGER実行時間
memory_used_mbINTEGERメモリ使用量
created_atTIMESTAMPTZDEFAULT NOW()開始時間
completed_atTIMESTAMPTZ完了時間
インデックス:
  • idx_agent_task_execution ON (task_execution_id)
  • idx_agent_created_at ON (created_at DESC)
  • idx_agent_state ON (state)
ステート値:
  • IDLE - エージェントアイドル
  • ANALYZING - 入力を分析中
  • PLANNING - 実行を計画中
  • RETRIEVING - 情報を取得中
  • EXECUTING - タスクを実行中
  • VALIDATING - 結果を検証中
  • SYNTHESIZING - レスポンスを合成中
  • COMPLETED - 実行完了
  • FAILED - 実行失敗
:
-- タスクのためのエージェント実行チェーン
SELECT agent_id, execution_order, state, duration_ms, tokens_used
FROM agent_executions
WHERE task_execution_id = '...'
ORDER BY execution_order;

-- エージェントパフォーマンスメトリクス
SELECT
    agent_id,
    COUNT(*) as execution_count,
    AVG(duration_ms) as avg_duration,
    AVG(tokens_used) as avg_tokens,
    SUM(cost_usd) as total_cost
FROM agent_executions
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY agent_id
ORDER BY execution_count DESC;

tool_executions

目的: ツール呼び出し履歴とパフォーマンス
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()実行 ID
agent_execution_idUUIDFK → agent_executions親エージェント
task_execution_idUUIDFK → task_executions親タスク
tool_nameVARCHAR(255)NOT NULLツール識別子
tool_versionVARCHAR(50)ツールバージョン
categoryVARCHAR(100)ツールカテゴリ
input_paramsJSONB入力パラメータ
outputJSONBツール出力
successBOOLEANDEFAULT true成功ステータス
error_messageTEXTエラー詳細
duration_msINTEGER実行時間
tokens_consumedINTEGERDEFAULT 0使用トークン
sandboxedBOOLEANDEFAULT trueWASI サンドボックス使用
memory_used_mbINTEGERメモリ使用量
executed_atTIMESTAMPTZDEFAULT NOW()実行時間
インデックス:
  • idx_tool_name ON (tool_name)
  • idx_tool_executed_at ON (executed_at DESC)
  • idx_tool_task_execution ON (task_execution_id)
  • idx_tool_success ON (success)
ツールカテゴリ:
  • search - 検索およびルックアップツール
  • calculation - 数学的および計算ツール
  • file - ファイルシステム操作
  • api - API 呼び出しおよび統合
  • code - コード実行および分析
:
-- ツール使用統計
SELECT
    tool_name,
    COUNT(*) as invocation_count,
    COUNT(CASE WHEN success THEN 1 END) as successful,
    AVG(duration_ms) as avg_duration
FROM tool_executions
WHERE executed_at > NOW() - INTERVAL '7 days'
GROUP BY tool_name
ORDER BY invocation_count DESC;

-- 失敗したツール実行
SELECT tool_name, error_message, executed_at
FROM tool_executions
WHERE success = false
  AND executed_at > NOW() - INTERVAL '24 hours'
ORDER BY executed_at DESC;

-- ツールパフォーマンス
SELECT
    tool_name,
    AVG(duration_ms) as avg_ms,
    MAX(duration_ms) as max_ms,
    STDDEV(duration_ms) as stddev_ms
FROM tool_executions
WHERE success = true
GROUP BY tool_name
ORDER BY avg_ms DESC;

event_logs

目的: 監査およびリプレイのためのイベントストレージ
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()イベントID
workflow_idVARCHAR(255)NOT NULLワークフロー識別子
task_idUUIDタスク参照(nullable)
typeVARCHAR(100)NOT NULLイベントタイプ
agent_idVARCHAR(255)エージェント識別子
messageTEXTイベントメッセージ
payloadJSONBDEFAULT ''イベントペイロード
timestampTIMESTAMPTZNOT NULL, DEFAULT NOW()イベント時間
seqBIGINTシーケンス番号
stream_idVARCHAR(64)RedisストリームID
created_atTIMESTAMPTZNOT NULL, DEFAULT NOW()レコード作成
インデックス:
  • idx_event_logs_workflow_id ON (workflow_id)
  • idx_event_logs_task_id ON (task_id)
  • idx_event_logs_type ON (type)
  • idx_event_logs_ts ON (timestamp DESC)
  • idx_event_logs_seq ON (workflow_id, seq)
  • idx_event_logs_workflow_ts ON (workflow_id, timestamp DESC)
  • uq_event_logs_wf_type_seq UNIQUE ON (workflow_id, type, seq) WHERE seq IS NOT NULL
イベントタイプ:
  • task.started - タスク実行開始
  • task.completed - タスク実行完了
  • agent.thinking - エージェント処理中
  • tool.called - ツール呼び出し
:
-- タスクのすべてのイベントを取得
SELECT type, agent_id, message, timestamp
FROM event_logs
WHERE workflow_id = '...'
ORDER BY timestamp;

-- イベント頻度分析
SELECT
    type,
    COUNT(*) as event_count,
    DATE_TRUNC('hour', timestamp) as hour
FROM event_logs
WHERE timestamp > NOW() - INTERVAL '24 hours'
GROUP BY type, hour
ORDER BY hour DESC, event_count DESC;

token_usage

目的: タスクごとの詳細なトークン使用状況の追跡
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()レコードID
user_idUUIDFK → usersユーザー
task_idUUIDFK → task_executionsタスク
providerVARCHAR(50)NOT NULLLLMプロバイダー
modelVARCHAR(255)NOT NULLモデル名
prompt_tokensINTEGERNOT NULL入力トークン
completion_tokensINTEGERNOT NULL出力トークン
total_tokensINTEGERNOT NULL合計トークン
cost_usdDECIMAL(10,6)NOT NULLUSDでのコスト
created_atTIMESTAMPTZDEFAULT NOW()レコード時間
インデックス:
  • idx_token_usage_user_id ON (user_id)
  • idx_token_usage_created_at ON (created_at DESC)
  • idx_token_usage_provider_model ON (provider, model)
  • idx_token_usage_task_id ON (task_id)
:
-- プロバイダーごとのトークン使用状況
SELECT
    provider,
    model,
    COUNT(*) as call_count,
    SUM(total_tokens) as total_tokens,
    SUM(cost_usd) as total_cost
FROM token_usage
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY provider, model
ORDER BY total_cost DESC;

-- 日次トークントレンド
SELECT
    DATE(created_at) as date,
    SUM(total_tokens) as tokens,
    SUM(cost_usd) as cost
FROM token_usage
WHERE created_at > NOW() - INTERVAL '30 days'
GROUP BY DATE(created_at)
ORDER BY date;

usage_daily_aggregates

目的: 事前計算された日次使用統計
カラム制約説明
idUUIDPK, DEFAULT uuid_generate_v4()レコードID
user_idUUIDFK → usersユーザー
dateDATENOT NULL集計日
total_tasksINTEGERDEFAULT 0合計タスク数
successful_tasksINTEGERDEFAULT 0成功数
failed_tasksINTEGERDEFAULT 0失敗数
total_tokensINTEGERDEFAULT 0合計トークン
total_cost_usdDECIMAL(10,6)DEFAULT 0合計コスト
model_usageJSONBモデル分布
tools_invokedINTEGERDEFAULT 0ツール呼び出し数
tool_distributionJSONBツール使用分布
avg_duration_msINTEGER平均タスク時間
cache_hit_rateDECIMAL(3,2)キャッシュヒット率
created_atTIMESTAMPTZDEFAULT NOW()レコード時間
インデックス:
  • idx_usage_daily_user_date ON (user_id, date)
  • idx_usage_daily_date ON (date DESC)
ユニーク制約: (user_id, date) :
-- ユーザー使用状況の概要
SELECT date, total_tasks, successful_tasks, total_cost_usd
FROM usage_daily_aggregates
WHERE user_id = '...'
  AND date > CURRENT_DATE - INTERVAL '30 days'
ORDER BY date DESC;

-- 集計メトリクス
SELECT
    SUM(total_tasks) as total_tasks,
    SUM(total_cost_usd) as total_cost,
    AVG(cache_hit_rate) as avg_cache_rate
FROM usage_daily_aggregates
WHERE date > CURRENT_DATE - INTERVAL '7 days';

追加テーブル

tool_calls

目的: レガシーツール呼び出しの追跡(代わりに tool_executions を使用)

prompts

目的: プロンプトのバージョン管理とA/Bテスト

learning_cases

目的: 強化学習ケースのストレージ

session_archives

目的: Redisからの長期セッションスナップショット

audit_logs (public)

目的: アプリケーション監査トレイル(auth.audit_logsとは別)

データベース関数

update_updated_at_column()

目的: 行の変更時に updated_at を自動的に更新 使用法: users および sessions テーブルにトリガーとして添付
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

update_daily_aggregate(user_id, date)

目的: ユーザーのために日次使用集計を更新または作成 使用法: タスク完了時にトリガーを介して自動的に呼び出される
-- 手動呼び出し
SELECT update_daily_aggregate(
    '00000000-0000-0000-0000-000000000002',
    '2025-10-22'
);

trigger_update_daily_aggregate()

目的: タスクのステータス変更時に集計を更新するトリガー関数 使用法: task_executions の INSERT/UPDATE 時に自動的に発火

サンプルクエリ

タスク分析

-- モード別タスク成功率
SELECT
    mode,
    COUNT(*) as total,
    COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) as completed,
    ROUND(100.0 * COUNT(CASE WHEN status = 'COMPLETED' THEN 1 END) / COUNT(*), 2) as success_rate
FROM task_executions
WHERE started_at > NOW() - INTERVAL '7 days'
GROUP BY mode;

-- 複雑さ別平均実行時間
SELECT
    CASE
        WHEN complexity_score < 0.3 THEN 'Low'
        WHEN complexity_score < 0.7 THEN 'Medium'
        ELSE 'High'
    END as complexity,
    COUNT(*) as task_count,
    AVG(duration_ms) as avg_ms,
    AVG(total_cost_usd) as avg_cost
FROM task_executions
WHERE complexity_score IS NOT NULL
GROUP BY complexity;

コスト分析

-- コスト上位ユーザー
SELECT
    u.email,
    COUNT(t.id) as task_count,
    SUM(t.total_cost_usd) as total_cost,
    AVG(t.total_cost_usd) as avg_cost
FROM task_executions t
JOIN users u ON t.user_id = u.id
WHERE t.started_at > NOW() - INTERVAL '30 days'
GROUP BY u.email
ORDER BY total_cost DESC
LIMIT 10;

-- モデル別コスト内訳
SELECT
    tu.provider,
    tu.model,
    COUNT(*) as usage_count,
    SUM(tu.total_tokens) as total_tokens,
    SUM(tu.cost_usd) as total_cost,
    AVG(tu.cost_usd) as avg_cost_per_call
FROM token_usage tu
WHERE tu.created_at > NOW() - INTERVAL '7 days'
GROUP BY tu.provider, tu.model
ORDER BY total_cost DESC;

パフォーマンス監視

-- 遅いクエリ (タスク > 60秒)
SELECT
    workflow_id,
    query,
    duration_ms,
    agents_used,
    tools_invoked
FROM task_executions
WHERE duration_ms > 60000
  AND started_at > NOW() - INTERVAL '24 hours'
ORDER BY duration_ms DESC;

-- ツール実行成功率
SELECT
    tool_name,
    COUNT(*) as total,
    COUNT(CASE WHEN success THEN 1 END) as successful,
    ROUND(100.0 * COUNT(CASE WHEN success THEN 1 END) / COUNT(*), 2) as success_rate,
    AVG(duration_ms) as avg_duration
FROM tool_executions
GROUP BY tool_name
ORDER BY total DESC;

ベストプラクティス

1. インデックス作成

常にインデックスを使用するべき:
  • 外部キー列 (user_id, tenant_id, task_execution_id など)
  • 頻繁にフィルタリングされる列 (status, created_at, expires_at)
  • JSONB クエリ (context->>‘external_id’)
  • 時間ベースのクエリ (created_at DESC)
現在のインデックスカバレッジ: 優秀 (すべての外部キーと一般的なクエリがインデックス化されている)

2. パーティショニング

高ボリュームのテーブルにはパーティショニングを検討:
-- task_executions の月次パーティショニング
CREATE TABLE task_executions_2025_10 PARTITION OF task_executions
    FOR VALUES FROM ('2025-10-01') TO ('2025-11-01');

3. データ保持

推奨ポリシー:
  • event_logs: 90日 (高ボリューム、アーカイブ可能)
  • task_executions: 1年 (古いデータをアーカイブ)
  • audit_logs: 2年 (コンプライアンス)
  • token_usage: 日次集計、90日後に生データをアーカイブ
クリーンアップスクリプト:
-- 古いイベントを削除 (毎月実行)
DELETE FROM event_logs
WHERE created_at < NOW() - INTERVAL '90 days';

-- 古いタスクをアーカイブ (毎年実行)
INSERT INTO task_executions_archive
SELECT * FROM task_executions
WHERE started_at < NOW() - INTERVAL '1 year';

DELETE FROM task_executions
WHERE started_at < NOW() - INTERVAL '1 year';

4. クエリ最適化

EXPLAIN ANALYZE を使用:
EXPLAIN ANALYZE
SELECT * FROM task_executions
WHERE user_id = '...'
  AND started_at > NOW() - INTERVAL '7 days';
カバリングインデックスで最適化:
CREATE INDEX idx_task_user_date_status
ON task_executions(user_id, started_at, status)
INCLUDE (total_cost_usd, duration_ms);

5. コネクションプーリング

設定 (Shannon ですでに設定済み):
DB_MAX_OPEN_CONNS=50
DB_MAX_IDLE_CONNS=10

メンテナンス

Vacuum と Analyze

-- 手動バキューム (毎週実行)
VACUUM ANALYZE task_executions;
VACUUM ANALYZE event_logs;

-- 自動バキュームの設定
ALTER TABLE task_executions SET (autovacuum_vacuum_threshold = 1000);

統計

-- 統計を更新
ANALYZE task_executions;

-- テーブルの膨張をチェック
SELECT
    schemaname,
    tablename,
    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

関連ドキュメント