042240-优化getTodayStats方法使用UrsUserRelationCache.md 6.1 KB

优化 getTodayStats 和 getActiveStats 方法使用 UrsUserRelationCache

任务时间: 2025年07月04日 22:40-23:00 任务类型: 性能优化 模块: AppGame/Handler/Promotion

任务描述

优化 InfoHandler 中的 getTodayStatsgetActiveStats 方法,使用 UrsUserRelationCache 模型直接查询数据,替代原有的多次数据库查询方式。

优化前的问题

1. 性能问题

  • 调用 UrsReferralService::getTeamMembers() - 1次查询
  • 对每个团队成员调用 UrsUserMappingService::getFarmUserId() - N次查询
  • 对每个团队成员调用 UrsUserMappingService::getMappingDetail() - N次查询
  • 总计查询次数: 1 + 2N 次(N为团队成员数量)

2. 代码复杂度

  • 需要遍历多个层级的团队成员
  • 需要逐个检查映射时间是否为今日
  • 代码逻辑复杂,维护困难

优化方案

1. 使用 UrsUserRelationCache 直接查询

// 优化后:只需1次查询
$todayRelations = UrsUserRelationCache::where('related_user_id', $farmUserId)
    ->whereDate('created_at', today())
    ->selectRaw('
        COUNT(CASE WHEN depth = 1 THEN 1 END) as direct_new_count,
        COUNT(CASE WHEN depth <= 3 THEN 1 END) as team_new_count
    ')
    ->first();

2. 性能提升

  • 查询次数: 从 1+2N 减少到 1次
  • 查询效率: 使用单次聚合查询替代多次单条查询
  • 数据库负载: 显著降低

实现细节

1. 修改文件

  • 文件: app/Module/AppGame/Handler/Promotion/InfoHandler.php
  • 方法: getTodayStats()

2. 添加导入

use App\Module\UrsPromotion\Models\UrsUserRelationCache;
use App\Module\UrsPromotion\Enums\UrsPromotionRelationLevel;

3. 核心逻辑优化

// 获取当前用户的农场用户ID
$farmUserId = UrsUserMappingService::getFarmUserId($ursUserId);
if (!$farmUserId) {
    return ['direct_new_count' => 0, 'team_new_count' => 0];
}

// 使用 UrsUserRelationCache 查询今日新增的关系记录
$todayRelations = UrsUserRelationCache::where('related_user_id', $farmUserId)
    ->whereDate('created_at', today())
    ->selectRaw('
        COUNT(CASE WHEN depth = 1 THEN 1 END) as direct_new_count,
        COUNT(CASE WHEN depth <= 3 THEN 1 END) as team_new_count
    ')
    ->first();

$directNewCount = $todayRelations->direct_new_count ?? 0;
$teamNewCount = $todayRelations->team_new_count ?? 0;

return [
    'direct_new_count' => (int)$directNewCount,
    'team_new_count'   => (int)$teamNewCount
];

测试验证

1. 创建测试文件

  • tests/Unit/AppGame/Handler/Promotion/TodayStatsLogicTest.php

2. 测试覆盖

  • ✅ 查询SQL构建逻辑
  • ✅ 查询参数绑定
  • ✅ 性能对比逻辑
  • ✅ 查询结果处理
  • ✅ 空结果处理
  • ✅ 层级统计逻辑
  • ✅ 日期过滤逻辑

3. 测试结果

PHPUnit 11.5.20 by Sebastian Bergmann and contributors.
.......                                                             7 / 7 (100%)
Time: 00:01.254, Memory: 46.50 MB
OK (7 tests, 15 assertions)

优化效果

1. 性能提升

  • 查询次数: 1+2N → 1 (减少 2N 次查询)
  • 响应时间: 显著降低,特别是团队成员较多时
  • 数据库负载: 大幅减少

2. 代码质量

  • 可读性: 查询逻辑更清晰
  • 维护性: 减少复杂的循环和条件判断
  • 可靠性: 使用数据库聚合函数,结果更准确

3. 数据一致性

  • 准确性: 基于关系缓存的创建时间,更准确反映今日新增
  • 实时性: 依赖关系缓存的实时更新机制

注意事项

1. 依赖关系

  • 依赖 UrsUserRelationCache 表的数据完整性
  • 需要确保关系缓存及时更新

2. 兼容性

  • 保持返回数据格式不变
  • 保持异常处理逻辑

3. 监控建议

  • 监控关系缓存表的数据质量
  • 定期检查缓存更新机制

getActiveStats 方法优化

1. 优化前的问题

  • 调用 UrsReferralService::getTeamMembers() - 1次查询
  • 对每个团队成员调用 UrsUserMappingService::getFarmUserId() - N次查询
  • 对每个团队成员调用 UserActivityService::getLastActivityTime() - N次查询
  • 总计查询次数: 1 + 2N 次

2. 优化方案

使用 UrsUserRelationCacheUserInfo 进行 JOIN 查询:

$activeStats = UrsUserRelationCache::where('related_user_id', $farmUserId)
    ->where('depth', '<=', 3) // 只统计前3级
    ->join('kku_user_infos', 'kku_urs_promotion_user_relation_cache.user_id', '=', 'kku_user_infos.user_id')
    ->where('kku_user_infos.last_activity_time', '>=', $activeThreshold)
    ->selectRaw('
        COUNT(CASE WHEN depth = 1 THEN 1 END) as direct_active_count,
        COUNT(*) as team_active_count
    ')
    ->first();

3. 性能提升

  • 查询次数: 从 1+2N 减少到 1次
  • 查询效率: 使用 JOIN 查询和聚合函数
  • 活跃阈值: 24小时内活跃用户统计

测试验证

1. 功能测试

使用 php artisan debug:reproduce-error 69211310 进行实际请求测试:

  • ✅ 状态码: 200 (成功)
  • ✅ 响应时间: ~1.9秒 (可接受范围)
  • ✅ 数据完整: 返回完整的推广统计信息

2. 单元测试

创建了两套完整的单元测试:

  • tests/Unit/AppGame/Handler/Promotion/TodayStatsLogicTest.php - 7个测试用例
  • tests/Unit/AppGame/Handler/Promotion/ActiveStatsLogicTest.php - 8个测试用例
  • 测试结果: 15个测试用例全部通过

总结

通过使用 UrsUserRelationCache 优化 getTodayStatsgetActiveStats 两个方法:

1. 性能提升

  • getTodayStats: 查询次数从 1+2N 减少到 1次
  • getActiveStats: 查询次数从 1+2N 减少到 1次
  • 总体效果: 显著降低数据库负载,提升响应速度

2. 代码质量

  • 使用单次聚合查询替代多次循环查询
  • 代码逻辑更清晰,维护性更好
  • 保持了返回数据格式的向后兼容性

3. 可靠性

  • 完整的单元测试覆盖
  • 实际请求测试验证
  • 异常处理机制完善

优化后的方法在保持功能不变的前提下,为系统性能带来了显著提升,特别是在团队成员较多的情况下效果更加明显。