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

3.7 KiB
Raw Blame History

痛点定位

  • 新用户接口在单次请求内对每个用户做多次单表查询(资产、道具卡、优惠券、称号、最后在线时间),形成 N+1 查询,延迟随列表大小线性增加(internal/api/admin/dashboard_admin.goDashboardNewUsers())。
  • 实时抽奖动态接口对每条抽奖日志逐条联查用户/期/活动/奖品,亦为 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 usersactivity_issuesactivitiesactivity_reward_settings,一次性返回 nickname/activityName/issueNumber/prizeName
    • 保留 since_id + limit 增量拉取;避免循环内 First() 调用
  • 预聚合与缓存
    • 建议增加 user_stats 表(或 Redis 缓存)维护:points_balanceinventory_countitem_card_countcoupon_counttitle_listlast_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 预聚合与写路径刷新机制

确认后我将按上述方案逐条落地并提供压测数据与对比报告。