database
GitHub管理 LLM Gateway Postgres 数据库,涵盖使用 Drizzle 进行 Schema 变更、数据迁移、查询构建及性能优化。支持读写操作、分析报表生成及本地环境初始化,确保数据一致性与高效访问。
触发场景
安装
npx skills add theopenco/llmgateway --skill database -g -y
SKILL.md
Frontmatter
{
"name": "database",
"description": "Query and change the LLM Gateway Postgres schema with Drizzle — reads, raw SQL, analytics and usage queries, the log table versus the hourly aggregation tables, used_model ids, cost sums, cached queries, and new columns. Use when editing packages\/db\/src\/schema.ts, writing Drizzle or raw SQL, building dashboards, stats, or usage reports, adding an organization column, or pushing and seeding the local database. For migration files use the migrations skill."
}
Database
Run commands from the repository root.
pnpm push— push the schema to the dev (pnpm push-dev) and test (pnpm push-test) databases.pnpm seed— seed data.pnpm run setup— reset, push, and seed (use thelocal-stackskill first).
Schema changes
Edit packages/db/src/schema.ts, then use the migrations skill. Refresh local
state with pnpm run setup. Production applies migrations before rolling out
new images, so new code may rely on new columns and backfills at startup.
A new organization column goes into SerializedOrganization's Omit list
(packages/db/src/types.ts) when internal, or into the /orgs response schemas
when the dashboard shows it; apps/ui derives its type from it. Confirm with a
full pnpm build.
Queries
- Use Drizzle's object syntax; reads via
db().query.<table>.findMany()/findFirst(). - Columns are camelCase in TypeScript and snake_case in the database (tables use
snakeCase.table, socolumn.nameis the snake_case name); raw SQL usesuser_id, notuserId. - Usage and analytics read the hourly aggregation tables:
project_hourly_stats,project_hourly_model_stats(addsused_model/used_provider),project_hourly_source_stats(addssource),api_key_hourly_stats,api_key_hourly_model_stats,global_model_stats,global_source_stats. Joinproject→organizationfor org fields such asbilling_email. Querylogonly for data no aggregate holds (payloads,request_idlookups, individual finish reasons), and say why. logcan hold billions of rows, takes an insert per request, and holds prompts, completions, and tool payloads. Retention nulls its payload columns but never deletes rows, so an unbounded scan covers the full history.- Bound every
logread by an indexed leading column (project_id,api_key_id, …) and bycreated_aton both ends. A keyset cursor written ascreated_at > c OR (created_at = c AND id > i)gives no index lower bound; addcreated_at >= c.EXPLAIN (ANALYZE, BUFFERS)against data skewed toward one large org, where plans that are cheap for small orgs flip to scans from the start of the index. created_athas microsecond precision and a JSDatekeeps milliseconds, so a cursor round-tripped through Drizzle re-matches its own row. Keep the cursor as text or comparedate_trunc('milliseconds', created_at).- Select
logpayload columns only when the feature needs them, and send them outside the platform only on an explicit opt-in. - The gateway request path reads no
logrows at all; hot-path signals come from Redis counters maintained on the write path or small cached rows. used_modelstoresprovider/model[:region]. Compare with catalogue ids aftersplit_part(split_part(used_model, '/', 2), ':', 1)(as instats-calculator.ts), and use the same shape in seeds and fixtures.- Cost columns are
real, andSUM(real)accumulates in float4. Sum asSUM(CAST(col AS DOUBLE PRECISION)); for exact readsSUM(CAST(CAST(col AS DOUBLE PRECISION) AS NUMERIC)).real::numericrounds to 6 digits. - Coordinate settings updates by validating state at each write boundary; advisory locks such as
pg_advisory_xact_lockare not used (the migration runner's advisory lock is the only one).
Cached client
The cached client stores positional driver rows. Cache keys are namespaced by
SCHEMA_CACHE_VERSION (derived from schema.ts) and runMigrations clears
them, so a column change needs no manual bump.
版本历史
-
c6810b7
当前 2026-11-02 20:57
修复迁移运行器并发锁冲突问题,引入锁超时与重试机制,解决因长查询阻塞导致的部署失败风险。
- d41bf19 2026-10-19 04:12


