perf(admin): GET /admin/host/self 卡 28s —— 补 2 个复合索引
getStats() 并发跑 10 条查询,其中两条缺覆盖索引: - patient_transactions.count(hostId, occurredAt>=X):(patient_id, occurred_at) 索引带不动"只按时间不带 patient_id"的过滤,近乎全扫索引。线上冷执行 8.3s。 - patient_facts.count(hostId, status='active'):(hostId, tenantId) 没 status、 (patientId, status) 没 hostId,两个都覆盖不了。线上冷执行 18.9s。 三列(非二列):tenant-guard 扩展对未带 tenantId 的查询自动注入 tenantId 过滤, 二列索引配上这条自动追加的谓词后 planner 直接弃用索引退回全表扫,三列才稳定命中 index-only scan。 两条索引都用 CREATE INDEX CONCURRENTLY(表已 379万/371万行,避免锁表阻塞摄入写入)。 线上手动建索引 + 验证已完成(index-only scan,查询从 8~19s 降到 <1s;端到端 GET /admin/host/self 28s → 0.9s);IF NOT EXISTS 保证下次 `prisma migrate deploy` 在 pac-migrate 里重跑时是空操作,只补 `_prisma_migrations` 记录。