bindbox-game/.trae/documents/优化“新用户”和“实时抽奖”接口性能.md
邹方成 87ad4177b1
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
feat(工作台): 实现管理端工作台接口并优化数据展示
feat(抽奖动态): 修复抽奖动态未渲染问题并优化文案展示
fix(用户概览): 修复用户概览无数据显示问题
feat(新用户列表): 在新用户列表显示称号明细
refactor(待办事项): 移除代办模块并全宽展示实时动态
feat(批量操作): 限制为单用户操作并在批量时提醒
fix(称号分配): 防重复分配称号的改造计划
perf(接口性能): 优化新用户和抽奖动态接口性能
feat(订单漏斗): 优化订单转化漏斗指标计算
docs(测试计划): 完善盲盒运营API核查与闭环测试计划
2025-11-16 14:00:29 +08:00

52 lines
3.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 痛点定位
- 新用户接口在单次请求内对每个用户做多次单表查询(资产、道具卡、优惠券、称号、最后在线时间),形成 N+1 查询,延迟随列表大小线性增加(`internal/api/admin/dashboard_admin.go``DashboardNewUsers()`)。
- 实时抽奖动态接口对每条抽奖日志逐条联查用户/期/活动/奖品,亦为 N+1 查询(`DashboardDrawStream()`)。
## 后端优化方案
- 批量聚合替代逐条查询NewUsers
- 第一步:一次查出当前页的 `user_id` 列表
- 第二步:分别对各表做分组聚合(单次查询):
- 资产:`SELECT user_id, COUNT(*) FROM user_inventory WHERE user_id IN (...) GROUP BY user_id`
- 道具卡:`SELECT user_id, COUNT(*) FROM user_item_cards WHERE status=1 AND user_id IN (...) GROUP BY user_id`
- 优惠券:`SELECT user_id, COUNT(*) FROM user_coupons WHERE user_id IN (...) GROUP BY user_id`
- 称号:`SELECT ut.user_id, st.id, st.name FROM user_titles ut LEFT JOIN system_titles st ON st.id=ut.title_id WHERE ut.user_id IN (...)`
- 最后在线:分别取各行为表 `MAX(time)``user_id` 聚合,再在内存求最大值
- 积分余额:改为批量查 `user_points` 有效积分 `GROUP BY user_id`,或接入预聚合表(见下)
- 第三步:用 `map[user_id]value` 合并到用户列表,避免每行多次往返数据库
- 连接查询替代逐条补全DrawStream
- 单条 SQL 联查:`activity_draw_logs` LEFT JOIN `users``activity_issues``activities``activity_reward_settings`,一次性返回 `nickname/activityName/issueNumber/prizeName`
- 保留 `since_id + limit` 增量拉取;避免循环内 `First()` 调用
- 预聚合与缓存
- 建议增加 `user_stats` 表(或 Redis 缓存)维护:`points_balance``inventory_count``item_card_count``coupon_count``title_list``last_online_at`
- 更新策略:
- 同步:在相关写入路径(发放积分/道具卡/优惠券/称号、抽奖、下单)更新统计
- 异步crontab 每 1-5 分钟增量刷新
- 实时抽奖:为最近 50 条结果加 3-5 秒内存缓存LRU 或 Redis
- 限流与分页
- 新用户默认 `page_size=20`,最大 50实时抽奖 `limit<=100`
- 对于“今年”范围下分页检索控制页大小,避免一次返回过多用户
## 数据库与索引
- 新建/确认索引:
- `users(created_at)``users(id)`
- `activity_draw_logs(id DESC, user_id, issue_id, reward_id, created_at)`
- `user_inventory(user_id)``user_item_cards(user_id,status)``user_coupons(user_id)``user_titles(user_id,title_id)`
- `user_points(user_id, valid_end)``user_points_ledger(user_id, created_at)`
- 可选:为 `log_request(path, created_at)` 增加 `user_id` 字段与索引,精确“最后在线时间”
## 前端协同优化
- 新用户页签切换时:防抖 200ms保留上次结果并显示加载骨架避免空白闪烁
- 实时抽奖轮询:保持 5s追加条目后裁剪到 100-200 条以保证 DOM 轻量;使用 `ref` 持有列表(已改)
- 宽度问题:动态项允许换行并分两行展示(已改),避免不可见
## 验收指标
- 新用户接口:在 `page_size=20` 时 P95 响应时间 < 200ms本地数据量下
- 实时抽奖接口 `limit=50` P95 响应时间 < 150ms每轮轮询端到端显示时间 < 300ms
## 下一步实现内容(获批后执行)
1) 重写 `DashboardNewUsers()` 为批量聚合与合并映射
2) 重写 `DashboardDrawStream()` 为单次 LEFT JOIN 联查
3) 添加必要索引迁移脚本
4) 可选落地 `user_stats` 预聚合与写路径刷新机制
确认后我将按上述方案逐条落地并提供压测数据与对比报告