362 lines
12 KiB
Markdown
362 lines
12 KiB
Markdown
|
|
# 分销中心接口优化方案
|
|||
|
|
|
|||
|
|
## 一、当前接口分析
|
|||
|
|
|
|||
|
|
### 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. 性能瓶颈分析
|
|||
|
|
|
|||
|
|
#### 问题点:
|
|||
|
|
1. **查询次数过多** - 9个独立查询,多次往返数据库
|
|||
|
|
2. **重复JOIN** - 多次JOIN相同的表(`referral_bindings`, `users`)
|
|||
|
|
3. **无缓存机制** - 配置数据每次都重新查询
|
|||
|
|
|
|||
|
|
#### 影响:
|
|||
|
|
- **响应时间慢** - 9个查询串行执行,总耗时约 500-800ms
|
|||
|
|
- **数据库负载高** - 高并发时增加数据库压力
|
|||
|
|
- **小程序加载慢** - 用户体验差,需要loading提示
|
|||
|
|
|
|||
|
|
## 二、优化方案设计
|
|||
|
|
|
|||
|
|
### 优化策略
|
|||
|
|
|
|||
|
|
#### 1. **查询合并** - 减少数据库往返次数
|
|||
|
|
|
|||
|
|
**原方案:5个独立的单行统计查询**
|
|||
|
|
```
|
|||
|
|
1. SELECT users → 用户信息
|
|||
|
|
2. SELECT referral_bindings → 绑定统计
|
|||
|
|
3. SELECT referral_visits → 访问统计
|
|||
|
|
4. SELECT orders → 付款统计
|
|||
|
|
5. SELECT withdrawals → 提现统计
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化方案:1个聚合查询**
|
|||
|
|
```sql
|
|||
|
|
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字段有索引
|
|||
|
|
- ✅ 限制返回字段,减少数据传输量
|
|||
|
|
- ✅ 添加查询超时控制
|
|||
|
|
|
|||
|
|
**需要的索引:**
|
|||
|
|
```sql
|
|||
|
|
-- 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. **配置缓存** - 减少重复查询
|
|||
|
|
|
|||
|
|
**原方案:**
|
|||
|
|
```javascript
|
|||
|
|
// 每次请求都查询配置
|
|||
|
|
const config = await getConfig('referral_config')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优化方案:**
|
|||
|
|
```javascript
|
|||
|
|
// 使用内存缓存(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时加载)
|
|||
|
|
|
|||
|
|
```javascript
|
|||
|
|
// 方案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: 核心优化(立即实施)
|
|||
|
|
|
|||
|
|
1. **合并统计查询** ⭐⭐⭐
|
|||
|
|
- 将5个独立统计查询合并为1个聚合查询
|
|||
|
|
- 预计减少响应时间 60-70%
|
|||
|
|
- 影响范围:`app/api/referral/data/route.ts`
|
|||
|
|
|
|||
|
|
2. **添加数据库索引** ⭐⭐⭐
|
|||
|
|
- 为高频查询字段添加复合索引
|
|||
|
|
- 提升查询效率 30-50%
|
|||
|
|
- 影响范围:数据库 schema
|
|||
|
|
|
|||
|
|
3. **减少列表数据量** ⭐⭐
|
|||
|
|
- 将列表限制从50条减少到20条
|
|||
|
|
- 减少数据传输量 40%
|
|||
|
|
- 影响范围:查询 LIMIT 参数
|
|||
|
|
|
|||
|
|
### Phase 2: 进阶优化(可选)
|
|||
|
|
|
|||
|
|
4. **配置缓存** ⭐⭐
|
|||
|
|
- 使用内存缓存配置数据
|
|||
|
|
- 减少配置查询次数
|
|||
|
|
- 影响范围:`lib/db.ts`
|
|||
|
|
|
|||
|
|
5. **懒加载列表** ⭐
|
|||
|
|
- 按需加载不同Tab的数据
|
|||
|
|
- 进一步减少初始加载时间
|
|||
|
|
- 影响范围:前端 + 后端接口
|
|||
|
|
|
|||
|
|
### Phase 3: 长期优化(未来规划)
|
|||
|
|
|
|||
|
|
6. **Redis缓存** ⭐
|
|||
|
|
- 缓存用户分销数据(1分钟过期)
|
|||
|
|
- 适用于高并发场景
|
|||
|
|
- 需要额外的Redis服务
|
|||
|
|
|
|||
|
|
7. **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` 接口响应格式**完全兼容**原有格式,前端无需修改。
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"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分钟) |
|
|||
|
|
| 列表数据不够用 | 低 | 中 | 支持分页参数,按需加载更多 |
|
|||
|
|
|
|||
|
|
## 七、测试验证
|
|||
|
|
|
|||
|
|
### 性能测试
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 测试工具:Apache Bench
|
|||
|
|
ab -n 100 -c 10 "http://localhost:3000/api/referral/data?userId=xxx"
|
|||
|
|
|
|||
|
|
# 预期结果:
|
|||
|
|
# - 平均响应时间 < 300ms
|
|||
|
|
# - 95%请求 < 400ms
|
|||
|
|
# - 无失败请求
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 数据正确性测试
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 验证聚合查询结果与独立查询一致
|
|||
|
|
-- 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';
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 八、总结
|
|||
|
|
|
|||
|
|
### 核心优化点
|
|||
|
|
|
|||
|
|
1. ⭐⭐⭐ **合并统计查询** - 从5个查询减少到1个,性能提升最大
|
|||
|
|
2. ⭐⭐⭐ **添加数据库索引** - 确保查询效率,避免全表扫描
|
|||
|
|
3. ⭐⭐ **减少返回数据量** - 减少网络传输,加快响应速度
|
|||
|
|
4. ⭐ **配置缓存** - 减少重复查询,降低数据库负载
|
|||
|
|
|
|||
|
|
### 实施建议
|
|||
|
|
|
|||
|
|
**推荐方案:立即实施 Phase 1**
|
|||
|
|
- 合并统计查询
|
|||
|
|
- 添加数据库索引
|
|||
|
|
- 减少列表数据量
|
|||
|
|
|
|||
|
|
**预计收益:**
|
|||
|
|
- 响应时间减少 60-70%
|
|||
|
|
- 数据库负载减少 50%
|
|||
|
|
- 用户体验显著提升
|
|||
|
|
|
|||
|
|
**实施时间:**
|
|||
|
|
- 开发时间:2-3小时
|
|||
|
|
- 测试时间:1小时
|
|||
|
|
- 部署时间:30分钟
|
|||
|
|
- **总计:约半天**
|
|||
|
|
|
|||
|
|
优化后,分销中心将成为一个高性能、低延迟的功能模块,为用户提供流畅的体验!🚀
|