perf(core): Wave 2 part1 — 复合索引(只生成不apply) + 消息中心 N+1 治理

索引(只 makemigrations 看 SQL,远程 MySQL apply 留用户低峰 / rule 3):
- Asset (team,category,-created_at)+(team,asset_type)、CreditLedger (team,-created_at)+
  (team,ledger_type,created_at)、Project (team,-updated_at)、AITask (team,-created_at)、
  Product (team,-created_at);迁移 assets0005/billing0002/projects0004/ai0008/products0002

消息中心 N+1(ops/views.py):
- type_counts 原 6 次 count(每请求)→ 一次 aggregate(Count(filter=...)) 条件聚合
- ensure_team_notifications 项目花费原逐项目 aggregate(N+1)→ 一次 values('project').annotate(Sum)

验证: apps.ops 测试 3/3 OK;全量 6fail+1err 均为预存 image provider 路由失败(stash 跑 baseline
  复现)= 零新增回归;索引迁移在 sqlite 测试库成功 apply

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-19 04:18:30 +08:00
co-authored by Claude Opus 4.8
parent 42c3c046ea
commit 99a442e883
12 changed files with 182 additions and 14 deletions
+19 -1
View File
@@ -29,7 +29,25 @@
---
## Wave 1 · 系统性 CSS/组件 (S1-S9) — ⏳ 进行中
## Wave 2 · 后端查询治理 — ⏳ 进行中
### part 1 — ✅ 完成 (2026-06-19)
| # | 项 | 状态 | 改动 / 证据 |
|---|---|---|---|
| 索引 | 复合索引(只 makemigrations 看 SQL,**未 apply 远程库**) | ✅ | 5 模型补复合索引:Asset `(team,category,-created_at)`+`(team,asset_type)`、CreditLedger `(team,-created_at)`+`(team,ledger_type,created_at)`(替原 `(team,ledger_type)`)、Project `(team,-updated_at)`、AITask `(team,-created_at)`、Product `(team,-created_at)`。生成迁移 assets/0005·billing/0002·projects/0004·ai/0008·products/0002,`sqlmigrate` 看到的都是干净 `CREATE INDEX`(+billing 一条 DROP 替换)。**远程 MySQL apply 留给用户低峰**(rule 3)。修了一处自摆乌龙:索引误加到 AssetFile,已挪回真正的 Asset 类。 |
| 消息 N+1 | type_counts + 项目花费聚合 | ✅ | `ops/views.py` `list()``type_counts`:原 6 次独立 `count()`(**每请求都跑**)→ 一次 `aggregate(Count(filter=...))` 条件聚合,少 5 个 DB 往返。`ensure_team_notifications` 首跑:5 个项目花费原**逐项目 aggregate**(N+1)→ 一次 `values('project').annotate(Sum)` 预聚合。 |
**part 1 验证:** `python manage.py test apps.ops`**3/3 OK**;全量 39 测试 6 fail+1 error **全部是预存** image_edit/provider 路由失败(stash 我的改动跑 baseline 42c3c04 复现同样失败)→ **零新增回归**(rule 11 ✅);索引迁移在 sqlite 测试库成功 apply(证迁移有效)。
### part 2 — ⏳ 待做(下一拍,起 celery + 浏览器 E2E)
- **poll-reviews 火山同步 HTTP 挪 Celery**(projects/views.py + assets/review.py;端点只读 DB review_status)——中风险,改审核轮询流,需 celery 起 + e2e。
- **写 action 瘦身**(projects 写 action 不回吐全量 ProjectSerializer;前端 `action()` 补 liteRefresh、refreshProjectDetail 仅 pipeline 页)——**最高风险**,贴近 pipeline 数据流(rule 3 敏感),需浏览器走查管线 refresh 不回归,专一拍做。
- **charge 通知 bulk_create**:暂缓 —— 仅后台 Celery 跑(非请求阻塞),且 `create_once` 创建+补字段二态耦合,裸批量改风险高 / 收益小,留作已知项。
---
## Wave 1 · 系统性 CSS/组件 (S1-S9) — ✅ 完成
> 为护住共享 CSS,拆两段做:**part 1 = 浮层/反馈(S3/S4/S9)**,part 2 = token/布局(S1/S2/S6/S7/S8)。