12 KiB
12 KiB
分销中心接口优化方案
一、当前接口分析
1. 接口调用情况
分销中心页面 (miniprogram/pages/referral/referral.js)
| 接口 | 调用时机 | 功能 | 优化空间 |
|---|---|---|---|
/api/referral/data |
页面初始化 | 获取所有分销数据 | ⚠️ 需优化查询数量 |
/api/miniprogram/qrcode |
用户点击分享 | 生成小程序码 | ✅ 合理 |
/api/withdraw |
用户申请提现 | 提现接口 | ✅ 合理 |
2. 核心接口 /api/referral/data 的查询情况
当前执行的数据库查询:
| 序号 | 查询目的 | 表 | 数据量 | 优化建议 |
|---|---|---|---|---|
| 1 | 获取用户基本信息 | users |
1行 | 🔄 可合并 |
| 2 | 获取绑定关系统计 | referral_bindings |
1行(聚合) | 🔄 可合并 |
| 3 | 获取访问量统计 | referral_visits |
1行(聚合) | 🔄 可合并 |
| 4 | 获取付款统计 | orders + referral_bindings |
1行(聚合) | 🔄 可合并 |
| 5 | 获取待审核提现金额 | withdrawals |
1行(聚合) | 🔄 可合并 |
| 6 | 获取活跃用户列表 | referral_bindings + users |
≤50行 | ✅ 保持独立 |
| 7 | 获取已转化用户列表 | referral_bindings + users |
≤50行 | ✅ 保持独立 |
| 8 | 获取已过期用户列表 | referral_bindings + users |
≤50行 | ✅ 保持独立 |
| 9 | 获取收益明细 | orders + users + referral_bindings |
≤30行 | ✅ 保持独立 |
总计:9个查询
3. 性能瓶颈分析
问题点:
- 查询次数过多 - 9个独立查询,多次往返数据库
- 重复JOIN - 多次JOIN相同的表(
referral_bindings,users) - 无缓存机制 - 配置数据每次都重新查询
影响:
- 响应时间慢 - 9个查询串行执行,总耗时约 500-800ms
- 数据库负载高 - 高并发时增加数据库压力
- 小程序加载慢 - 用户体验差,需要loading提示
二、优化方案设计
优化策略
1. 查询合并 - 减少数据库往返次数
原方案:5个独立的单行统计查询
1. SELECT users → 用户信息
2. SELECT referral_bindings → 绑定统计
3. SELECT referral_visits → 访问统计
4. SELECT orders → 付款统计
5. SELECT withdrawals → 提现统计
优化方案:1个聚合查询
SELECT
-- 用户信息
u.id, u.nickname, u.referral_code, u.earnings,
u.pending_earnings, u.withdrawn_earnings, u.referral_count,
-- 绑定统计(子查询)
(SELECT COUNT(*) FROM referral_bindings WHERE referrer_id = u.id) as total_bindings,
(SELECT COUNT(*) FROM referral_bindings WHERE referrer_id = u.id AND status = 'active' AND expiry_date > NOW()) as active_bindings,
(SELECT COUNT(*) FROM referral_bindings WHERE referrer_id = u.id AND status = 'active' AND purchase_count > 0) as converted_bindings,
(SELECT COUNT(*) FROM referral_bindings WHERE referrer_id = u.id AND (status = 'expired' OR expiry_date <= NOW())) as expired_bindings,
-- 访问统计(子查询)
(SELECT COUNT(DISTINCT visitor_id) FROM referral_visits WHERE referrer_id = u.id) as total_visits,
-- 付款统计(子查询)
(SELECT COUNT(DISTINCT o.user_id) FROM orders o JOIN referral_bindings rb ON o.user_id = rb.referee_id WHERE rb.referrer_id = u.id AND o.status = 'paid') as paid_count,
(SELECT COALESCE(SUM(o.amount), 0) FROM orders o JOIN referral_bindings rb ON o.user_id = rb.referee_id WHERE rb.referrer_id = u.id AND o.status = 'paid') as total_amount,
-- 待审核提现(子查询)
(SELECT COALESCE(SUM(amount), 0) FROM withdrawals WHERE user_id = u.id AND status = 'pending') as pending_withdraw_amount
FROM users u
WHERE u.id = ?
优势:
- ✅ 从5个查询减少到1个查询
- ✅ 减少数据库往返次数(从5次减少到1次)
- ✅ 响应时间减少约 60-70%
2. 列表查询优化 - 合理使用索引
当前查询:4个独立列表查询
- 活跃用户列表(50条)
- 已转化用户列表(50条)
- 已过期用户列表(50条)
- 收益明细(30条)
优化方案:
- ✅ 保持独立查询(列表数据无法合并)
- ✅ 确保所有JOIN字段有索引
- ✅ 限制返回字段,减少数据传输量
- ✅ 添加查询超时控制
需要的索引:
-- referral_bindings 表
CREATE INDEX idx_referrer_status_expiry ON referral_bindings(referrer_id, status, expiry_date);
CREATE INDEX idx_referrer_purchase ON referral_bindings(referrer_id, purchase_count);
-- orders 表
CREATE INDEX idx_user_status_paytime ON orders(user_id, status, pay_time);
CREATE INDEX idx_referrer_status ON orders(referrer_id, status);
-- withdrawals 表
CREATE INDEX idx_user_status ON withdrawals(user_id, status);
3. 配置缓存 - 减少重复查询
原方案:
// 每次请求都查询配置
const config = await getConfig('referral_config')
优化方案:
// 使用内存缓存(5分钟过期)
const configCache = new Map()
async function getCachedConfig(key) {
const cached = configCache.get(key)
if (cached && Date.now() - cached.time < 5 * 60 * 1000) {
return cached.data
}
const data = await getConfig(key)
configCache.set(key, { data, time: Date.now() })
return data
}
4. 分页加载 - 减少初始数据量
原方案:
- 一次性加载所有列表数据(活跃50条 + 转化50条 + 过期50条 + 明细30条 = 180条)
优化方案:
- 初始只加载核心统计数据 + 活跃用户列表(20条)
- 其他列表数据按需加载(用户切换Tab时加载)
// 方案1:单接口 + type参数
GET /api/referral/data?userId=xxx&type=overview // 只返回统计数据
GET /api/referral/data?userId=xxx&type=active // 活跃用户列表
GET /api/referral/data?userId=xxx&type=converted // 已转化列表
GET /api/referral/data?userId=xxx&type=expired // 已过期列表
GET /api/referral/data?userId=xxx&type=earnings // 收益明细
// 方案2:保持当前一次性加载(推荐)
// 理由:分销中心是高频页面,用户通常会查看所有数据
// 优化查询性能比拆分接口更有效
优化后的架构
┌─────────────────────────────────────────┐
│ 小程序 - 分销中心页面 │
└─────────────────┬───────────────────────┘
│
│ 1次请求
↓
┌─────────────────────────────────────────┐
│ /api/referral/data (优化后) │
├─────────────────────────────────────────┤
│ 1. 聚合统计查询(1个查询) │
│ - 用户信息 + 绑定统计 + 付款统计 │
│ - 访问统计 + 提现统计 │
│ 2. 活跃用户列表(1个查询,20条) │
│ 3. 已转化用户列表(1个查询,20条) │
│ 4. 已过期用户列表(1个查询,20条) │
│ 5. 收益明细(1个查询,20条) │
├─────────────────────────────────────────┤
│ 总计:5个查询(vs 原9个查询) │
│ 预计响应时间:200-300ms(vs 原500-800ms)│
└─────────────────────────────────────────┘
三、实施计划
Phase 1: 核心优化(立即实施)
-
合并统计查询 ⭐⭐⭐
- 将5个独立统计查询合并为1个聚合查询
- 预计减少响应时间 60-70%
- 影响范围:
app/api/referral/data/route.ts
-
添加数据库索引 ⭐⭐⭐
- 为高频查询字段添加复合索引
- 提升查询效率 30-50%
- 影响范围:数据库 schema
-
减少列表数据量 ⭐⭐
- 将列表限制从50条减少到20条
- 减少数据传输量 40%
- 影响范围:查询 LIMIT 参数
Phase 2: 进阶优化(可选)
-
配置缓存 ⭐⭐
- 使用内存缓存配置数据
- 减少配置查询次数
- 影响范围:
lib/db.ts
-
懒加载列表 ⭐
- 按需加载不同Tab的数据
- 进一步减少初始加载时间
- 影响范围:前端 + 后端接口
Phase 3: 长期优化(未来规划)
-
Redis缓存 ⭐
- 缓存用户分销数据(1分钟过期)
- 适用于高并发场景
- 需要额外的Redis服务
-
CDN缓存 ⭐
- 缓存小程序码图片
- 减少生成次数
- 需要CDN服务支持
四、性能对比
优化前 vs 优化后
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 数据库查询次数 | 9个 | 5个 | ↓ 44% |
| 聚合查询次数 | 5个 | 1个 | ↓ 80% |
| 列表查询次数 | 4个 | 4个 | - |
| 返回数据量 | ~180条 | ~80条 | ↓ 55% |
| 预计响应时间 | 500-800ms | 200-300ms | ↓ 60-70% |
| 数据库负载 | 高 | 中 | ↓ 50% |
优化效果预估
用户体验提升:
- ✅ 页面加载速度提升 60-70%
- ✅ Loading时间更短,体验更流畅
- ✅ 数据刷新更快
服务器性能提升:
- ✅ 数据库查询减少 44%
- ✅ 数据库连接时间减少 60%
- ✅ 可支持更高并发
成本优化:
- ✅ 数据库资源消耗减少 50%
- ✅ 带宽消耗减少 55%
五、向后兼容
API响应格式
优化后的 /api/referral/data 接口响应格式完全兼容原有格式,前端无需修改。
{
"success": true,
"data": {
// 核心统计(不变)
"bindingCount": 10,
"visitCount": 50,
"paidCount": 5,
"expiredCount": 2,
// 收益数据(不变)
"totalCommission": 450.00,
"availableEarnings": 300.00,
"pendingWithdrawAmount": 100.00,
"withdrawnEarnings": 50.00,
// 列表数据(数量减少,格式不变)
"activeUsers": [...], // 50条 → 20条
"convertedUsers": [...], // 50条 → 20条
"expiredUsers": [...], // 50条 → 20条
"earningsDetails": [...] // 30条 → 20条
}
}
六、风险评估
| 风险 | 影响 | 概率 | 缓解措施 |
|---|---|---|---|
| 聚合查询性能不如预期 | 中 | 低 | 回滚到原查询,添加更多索引 |
| 复杂子查询导致慢查询 | 高 | 低 | 使用 EXPLAIN 分析,优化查询计划 |
| 缓存数据不一致 | 中 | 中 | 设置短期过期时间(5分钟) |
| 列表数据不够用 | 低 | 中 | 支持分页参数,按需加载更多 |
七、测试验证
性能测试
# 测试工具:Apache Bench
ab -n 100 -c 10 "http://localhost:3000/api/referral/data?userId=xxx"
# 预期结果:
# - 平均响应时间 < 300ms
# - 95%请求 < 400ms
# - 无失败请求
数据正确性测试
-- 验证聚合查询结果与独立查询一致
-- 1. 绑定统计
SELECT COUNT(*) FROM referral_bindings WHERE referrer_id = 'xxx';
-- 2. 付款统计
SELECT COUNT(DISTINCT o.user_id)
FROM orders o
JOIN referral_bindings rb ON o.user_id = rb.referee_id
WHERE rb.referrer_id = 'xxx' AND o.status = 'paid';
-- 3. 提现统计
SELECT SUM(amount) FROM withdrawals WHERE user_id = 'xxx' AND status = 'pending';
八、总结
核心优化点
- ⭐⭐⭐ 合并统计查询 - 从5个查询减少到1个,性能提升最大
- ⭐⭐⭐ 添加数据库索引 - 确保查询效率,避免全表扫描
- ⭐⭐ 减少返回数据量 - 减少网络传输,加快响应速度
- ⭐ 配置缓存 - 减少重复查询,降低数据库负载
实施建议
推荐方案:立即实施 Phase 1
- 合并统计查询
- 添加数据库索引
- 减少列表数据量
预计收益:
- 响应时间减少 60-70%
- 数据库负载减少 50%
- 用户体验显著提升
实施时间:
- 开发时间:2-3小时
- 测试时间:1小时
- 部署时间:30分钟
- 总计:约半天
优化后,分销中心将成为一个高性能、低延迟的功能模块,为用户提供流畅的体验!🚀