050009-Promotion-List接口性能优化.md 5.3 KB

Promotion-List接口性能优化

任务概述

修复 Promotion-List 接口的严重性能问题,该接口在查询推广团队成员列表时出现超时,执行时间超过2分钟。

任务时间

  • 开始时间:2025年07月05日 00:09:24 CST
  • 完成时间:2025年07月05日 00:15:00 CST
  • 总耗时:约6分钟

问题分析

1. 问题现象

  • 请求:Promotion-List,参数:{"page":{"page":"2","perPage":"10"},"level":"1"}
  • 执行时间:141168ms(约2.5分钟)
  • 最终超时失败:cURL error 28: Operation timed out after 30002 milliseconds
  • 日志显示大量SQL查询:select urs_user_id from kku_urs_promotion_user_referrals where urs_referrer_id = ? and status = 1

2. 根本原因

性能瓶颈在 getTeamMemberData 方法

  1. 第146行调用 UrsReferralService::getTeamMembers($ursUserId) 无参数,默认查询20代
  2. 即使用户只要1代数据(level=1),系统还是查询了20代所有数据
  3. getTeamMembers() 方法使用递归查询,对每个用户都调用 getDirectReferrals()
  4. 产生数百次数据库查询,造成性能爆炸

3. 逻辑问题

// 问题代码
$teamMembers = UrsReferralService::getTeamMembers($ursUserId); // 查询20代
if ($level == 1) {
    // 只使用1代数据,其他19代查询都是浪费
    $filteredMembers = $teamMembers[1];
}

解决方案

1. 使用缓存表优化查询

将递归查询改为使用 UrsUserRelationCache 缓存表:

优化前

// 递归查询20代,产生数百次SQL查询
$teamMembers = UrsReferralService::getTeamMembers($ursUserId);

优化后

// 直接查询缓存表,只查询指定层级
$query = UrsUserRelationCache::where('related_user_id', $farmUserId);
if ($level == 1) {
    $query->where('depth', 1); // 只查询1代
}

2. 数据库层面分页

优化前:查询所有数据后在内存中分页 优化后:在数据库层面进行分页查询

3. 精确查询层级

根据 level 参数精确查询指定层级,避免不必要的数据查询。

修改内容

1. 核心方法重构

文件:app/Module/AppGame/Handler/Promotion/ListHandler.php

主要修改

  • 重构 getTeamMemberData() 方法
  • 使用 UrsUserRelationCache 缓存表替代递归查询
  • 根据 level 参数精确查询指定层级
  • 在数据库层面进行分页
  • 移除不再使用的导入

关键查询优化

-- 统计总数
SELECT COUNT(*) FROM kku_urs_promotion_user_relation_cache 
WHERE related_user_id = ? AND depth = ?

-- 分页查询
SELECT * FROM kku_urs_promotion_user_relation_cache 
WHERE related_user_id = ? AND depth = ? 
ORDER BY depth ASC, user_id ASC 
LIMIT ? OFFSET ?

性能提升

1. 执行时间对比

  • 优化前:141168ms(约2.5分钟)
  • 优化后:3717ms(约3.7秒)
  • 性能提升:约 38倍

2. SQL查询对比

  • 优化前:数百次递归查询 urs_promotion_user_referrals
  • 优化后:2次查询 urs_promotion_user_relation_cache 表(count + select)

3. 资源消耗

  • 优化前:大量数据库连接和查询,内存占用高
  • 优化后:最小化数据库查询,内存占用低

测试验证

1. 功能测试

使用 php artisan debug:reproduce-error 69223552 重放原始请求:

  • ✅ 请求成功返回
  • ✅ 数据正确:total=54,返回第2页10条数据
  • ✅ 分页信息正确:currentPage=2, perPage=10, hasMore=true, lastPage=6

2. 性能测试

  • ✅ 执行时间从141秒降低到3.7秒
  • ✅ SQL查询从数百次降低到2次
  • ✅ 无超时错误

技术要点

1. 缓存表设计

UrsUserRelationCache 表的设计很好地支持了这种查询优化:

  • related_user_id:上级用户ID,用于查询某用户的所有下级
  • depth:层级深度,支持精确查询指定层级
  • 索引优化:支持高效的分页查询

2. 查询策略

  • 避免N+1查询问题
  • 使用数据库层面的分页和排序
  • 根据业务需求精确查询,避免过度查询

3. 向后兼容

  • 保持API接口不变
  • 返回数据格式完全一致
  • 不影响其他功能模块

业务影响

1. 用户体验提升

  • 推广列表加载速度大幅提升
  • 避免接口超时导致的用户体验问题
  • 提高系统响应性能

2. 系统稳定性

  • 减少数据库压力
  • 降低系统资源消耗
  • 提高并发处理能力

3. 可扩展性

  • 为后续功能扩展奠定基础
  • 缓存表设计支持更复杂的查询需求

提交记录

Commit: eb917d51

优化Promotion-List接口性能:使用缓存表替代递归查询

- 修改getTeamMemberData方法,使用UrsUserRelationCache缓存表查询
- 避免递归调用getTeamMembers方法查询20代数据的性能问题
- 根据level参数精确查询指定层级,避免不必要的数据查询
- 在数据库层面进行分页,提升查询效率
- 性能提升约38倍:从141秒优化到3.7秒
- 移除不再使用的UrsReferralService和AccountService导入

后续建议

1. 监控优化效果

  • 持续监控 Promotion-List 接口的性能表现
  • 关注缓存表的数据一致性

2. 类似问题排查

  • 检查其他使用 UrsReferralService::getTeamMembers() 的地方
  • 评估是否需要类似的优化

3. 缓存表维护

  • 确保 UrsUserRelationCache 表的数据及时更新
  • 监控缓存表的数据完整性