Skip to content

perf: reduce homepage database hot paths and chunk large key queries#287

Open
mozi1924 wants to merge 4 commits into
qxcnm:mainfrom
mozi1924:codex/homepage-db-hotpath-fix
Open

perf: reduce homepage database hot paths and chunk large key queries#287
mozi1924 wants to merge 4 commits into
qxcnm:mainfrom
mozi1924:codex/homepage-db-hotpath-fix

Conversation

@mozi1924
Copy link
Copy Markdown
Contributor

变更摘要

  • 将首页/仪表盘相关的 key 与 usage 汇总改成按当前用户或当前 key 范围直接查询,避免先全量聚合再在 Rust 侧过滤。
  • IN (...) key 列表查询做分批,规避 SQLite host parameter 上限,提升大 key 集合场景的稳定性。
  • 保留账号列表的 owned fast path,减少热路径上的不必要字符串 clone。
  • 补充 900+ key 的回归测试,覆盖 key 聚合、quota limit 和 key-model 聚合路径。

改动范围

  • Frontend
  • Desktop / Tauri
  • Service
  • Gateway / Protocol Adapter
  • Docs / Governance
  • Workflow / Release

主要文件

验证

  • cargo check -p codexmanager-core -p codexmanager-service
  • cargo test -p codexmanager-core summaries_for_large_key_lists_are_chunked -- --nocapture
  • cargo test -p codexmanager-core large_key_sets_are_chunked_for_api_key_and_quota_queries -- --nocapture
  • cargo test -p codexmanager-service --lib
  • pnpm -C apps run build
  • pnpm -C apps run test:runtime

已执行的实际验证:

cargo check -p codexmanager-core -p codexmanager-service
cargo test -p codexmanager-core summaries_for_large_key_lists_are_chunked -- --nocapture
cargo test -p codexmanager-core large_key_sets_are_chunked_for_api_key_and_quota_queries -- --nocapture
cargo test -p codexmanager-service --lib
cargo fmt --all --check

未执行的验证与原因:

pnpm -C apps run build
pnpm -C apps run test:runtime

本次变更仅涉及 Rust service/storage 层,没有触及前端或桌面运行时。

风险与影响面

  • 大 key 集合会被拆成多条 SQL 执行,但可以避免 SQLite 参数上限导致的查询失败。
  • 查询结果保持原有语义,只调整了查询范围和聚合方式,风险主要集中在性能回归而不是功能变更。

备注

  • 提交前请确认未包含敏感 token、cookie、API key。

Copy link
Copy Markdown
Collaborator

@KilimiaoSix KilimiaoSix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

本次 code review 不通过。主要问题是:PR 的核心热点优化没有完整接入服务层,部分新统计查询在大 key 集合下仍会重复扫描,并且新增 SQL/IN-list 逻辑存在明显重复,后续容易产生统计口径漂移。请优先修复下方阻塞项后再请求复审。

///
/// # 返回
/// 返回函数执行结果
pub fn list_api_key_ids_for_user(&self, user_id: &str) -> Result<Vec<String>> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里新增了按 owner_kind + owner_user_id 查询 key id 的索引路径,但服务层实际使用的 crate::list_api_key_ids_for_user 仍然调用 storage.list_api_key_owners() 拉全量 owner 后在 Rust 里过滤。因此成员 Dashboard、startup snapshot、API Key 页面仍会走旧热点路径,PR 的主要优化没有真正生效。建议把服务层 helper 改为调用这个新的 storage 方法,并补一个覆盖非 admin 路径的测试。

return Ok(Vec::new());
}
let mut items = Vec::new();
for chunk in normalized_key_ids.chunks(SQLITE_IN_CLAUSE_BATCH_SIZE) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里按 900 个 key 分 chunk 后,每个 chunk 都会重新执行一次包含 request_token_stats UNION ALL request_token_stat_rollups 的统计查询。用户/组织 key 数超过 900 时,成员用量页会按 chunk 数重复扫描 stats/rollup,性能开销会被放大。建议考虑临时表、VALUES CTE,或把 key 集合作为一次 join/filter 输入,避免每个 chunk 重新扫聚合来源。

let Some(clause) = key_id_filter_clause("key_id", key_ids, &mut params) else {
return Ok(Vec::new());
};
let mut stmt = self.conn.prepare(&format!(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

过滤版 by-key 查询基本复制了非过滤版统计 SQL;同一个文件里 by-model、by-key-and-model 也有类似的过滤/非过滤双份 SQL。后续如果调整 token total 计算、rollup 纳入规则、model 归一化、字段或排序,很容易只改一处,导致成员视角和管理员/全局统计口径漂移。建议抽出共享 query builder/row mapper,只把 key filter 作为可选条件拼进去。

Comment thread crates/core/src/storage/api_keys.rs Outdated
Ok(out)
}

fn normalize_key_ids(key_ids: &[String]) -> Vec<String> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalize_key_ids 以及 IN (?, ...) 占位符构造逻辑在 api_keys.rsapi_key_quota_limits.rsrequest_token_stats.rs 中重复出现。后续调整 batch size、空列表语义或 key id 规范化时需要改多份代码,容易产生不一致。建议提取一个 storage 层共享 helper,统一处理 normalize/chunk/placeholder 参数构造。

@mozi1924
Copy link
Copy Markdown
Contributor Author

已根据 review 反馈补充修复:

  • 服务层 list_api_key_ids_for_user 已接入 storage 的 owner_kind + owner_user_id 索引查询,成员 dashboard / startup snapshot / API Key 页面不再回退到全量 owner 扫描。
  • filtered token stats 聚合已从 chunked IN (...) 改为单次 temp table filter,避免大 key 集合下重复扫描 request_token_stats / request_token_stat_rollups
  • 抽出了 storage 层 key id helper,统一 normalize / batch size / IN-list 构造;API key 和 quota indexed lookup 继续复用该 helper。
  • 补了非 admin apikey/usageStats 回归测试,以及空 key 列表和大 key 列表的 token stats 回归测试。

验证已通过:

cargo check -p codexmanager-core -p codexmanager-service
cargo test -p codexmanager-core
env -u http_proxy -u https_proxy -u all_proxy -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY NO_PROXY=127.0.0.1,localhost cargo test -p codexmanager-service --lib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants