---
description: 后端性能优化和数据库查询优化
globs: ["**/server/**/*", "**/*.service.ts", "**/*.repository.ts", "**/*.controller.ts"]
alwaysApply: false
---

# 后端性能优化规范

## 🗄️ 数据库查询优化

### 避免 N+1 查询问题
```typescript
// services/user.service.ts
@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  // ❌ 错误示例 - N+1 查询
  async getUsersWithPostsBad(): Promise<User[]> {
    const users = await this.userRepository.find();
    for (const user of users) {
      user.posts = await this.postRepository.find({ where: { userId: user.id } });
    }
    return users;
  }

  // ✅ 正确示例 - 使用连接查询
  async getUsersWithPosts(): Promise<User[]> {
    return this.userRepository
      .createQueryBuilder('user')
      .leftJoinAndSelect('user.posts', 'post')
      .getMany();
  }

  // ✅ 使用批量查询
  async getUsersByIds(userIds: string[]): Promise<User[]> {
    return this.userRepository
      .createQueryBuilder('user')
      .where('user.id IN (:...userIds)', { userIds })
      .getMany();
  }
}
```

### 查询优化最佳实践
```typescript
// ✅ 查询优化示例
@Injectable()
export class UserRepository {
  constructor(
    @InjectRepository(User)
    private readonly repository: Repository<User>,
  ) {}

  // ✅ 使用索引优化查询
  async findByEmail(email: string): Promise<User | null> {
    return this.repository.findOne({
      where: { email },
      select: ['id', 'email', 'firstName', 'lastName'], // 只选择需要的字段
    });
  }

  // ✅ 分页查询
  async findUsersWithPagination(page: number, limit: number): Promise<[User[], number]> {
    return this.repository.findAndCount({
      skip: (page - 1) * limit,
      take: limit,
      order: { createdAt: 'DESC' },
    });
  }

  // ✅ 使用原生查询优化复杂查询
  async getUsersWithStats(): Promise<any[]> {
    return this.repository.query(`
      SELECT 
        u.id,
        u.email,
        u.first_name,
        u.last_name,
        COUNT(p.id) as post_count,
        MAX(p.created_at) as last_post_date
      FROM users u
      LEFT JOIN posts p ON u.id = p.user_id
      GROUP BY u.id
      ORDER BY post_count DESC
    `);
  }
}
```

## 🚀 缓存策略

### Redis 缓存实现
```typescript
// services/cache.service.ts
@Injectable()
export class CacheService {
  constructor(
    @InjectRedis() private readonly redis: Redis,
  ) {}

  // ✅ 缓存用户数据
  async cacheUser(userId: string, userData: any, ttl: number = 3600): Promise<void> {
    const key = `user:${userId}`;
    await this.redis.setex(key, ttl, JSON.stringify(userData));
  }

  // ✅ 获取缓存用户数据
  async getCachedUser(userId: string): Promise<any | null> {
    const key = `user:${userId}`;
    const cached = await this.redis.get(key);
    return cached ? JSON.parse(cached) : null;
  }

  // ✅ 缓存失效
  async invalidateUserCache(userId: string): Promise<void> {
    const key = `user:${userId}`;
    await this.redis.del(key);
  }

  // ✅ 批量缓存操作
  async cacheUsers(users: any[], ttl: number = 3600): Promise<void> {
    const pipeline = this.redis.pipeline();
    
    users.forEach(user => {
      const key = `user:${user.id}`;
      pipeline.setex(key, ttl, JSON.stringify(user));
    });
    
    await pipeline.exec();
  }
}
```

### NestJS 缓存装饰器
```typescript
// ✅ NestJS 缓存装饰器使用
@Injectable()
export class UserService {
  constructor(
    private readonly userRepository: UserRepository,
    private readonly cacheService: CacheService,
  ) {}

  @Cacheable({
    key: (userId: string) => `user:${userId}`,
    ttl: 3600, // 1小时
  })
  async findById(userId: string): Promise<User | null> {
    return this.userRepository.findById(userId);
  }

  @CacheEvict({
    key: (userId: string) => `user:${userId}`,
  })
  async updateUser(userId: string, updates: Partial<User>): Promise<User> {
    const user = await this.userRepository.update(userId, updates);
    return user;
  }
}
```

## ⚡ 异步处理和消息队列

### 消息队列处理
```typescript
// services/email.service.ts
@Injectable()
export class EmailService {
  constructor(
    @InjectQueue('email') private emailQueue: Queue,
  ) {}

  // ✅ 异步发送邮件
  async sendWelcomeEmail(userEmail: string, userName: string): Promise<void> {
    await this.emailQueue.add('welcome-email', {
      email: userEmail,
      name: userName,
      template: 'welcome',
    });
  }

  // ✅ 批量发送邮件
  async sendBulkEmail(recipients: string[], subject: string, content: string): Promise<void> {
    const jobs = recipients.map(email => ({
      name: 'bulk-email',
      data: { email, subject, content },
    }));
    
    await this.emailQueue.addBulk(jobs);
  }
}

// processors/email.processor.ts
@Processor('email')
export class EmailProcessor {
  constructor(private readonly mailService: MailService) {}

  @Process('welcome-email')
  async handleWelcomeEmail(job: Job<{ email: string; name: string }>) {
    const { email, name } = job.data;
    
    await this.mailService.sendMail({
      to: email,
      subject: '欢迎注册',
      template: 'welcome',
      context: { name },
    });
  }
}
```

## 📊 API 响应优化

### 响应压缩和分页
```typescript
// main.ts
import compression from 'compression';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // ✅ 响应压缩中间件
  app.use(compression({
    level: 6,
    threshold: 1024,
    filter: (req, res) => {
      if (req.headers['x-no-compression']) {
        return false;
      }
      return compression.filter(req, res);
    },
  }));
  
  await app.listen(3000);
}

// controllers/user.controller.ts
@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get()
  async getUsers(
    @Query('page') page: number = 1,
    @Query('limit') limit: number = 10,
    @Query('fields') fields?: string,
  ) {
    // ✅ 限制返回字段
    const selectFields = fields ? fields.split(',') : ['id', 'email', 'firstName', 'lastName'];
    
    return this.userService.findUsers({
      page,
      limit: Math.min(limit, 100), // 限制最大数量
      select: selectFields,
    });
  }

  @Get(':id')
  @UseInterceptors(CacheInterceptor)
  @CacheTTL(300) // 5分钟缓存
  async getUser(@Param('id') id: string) {
    return this.userService.findById(id);
  }
}
```

## 🎯 后端性能最佳实践

### 必需配置项
- ✅ 优化数据库查询，避免 N+1 问题
- ✅ 实现 Redis 缓存策略
- ✅ 使用消息队列处理异步任务
- ✅ 配置响应压缩和分页
- ✅ 设置适当的缓存 TTL

### 参考文件
- `services/user.service.ts` - 用户服务
- `services/cache.service.ts` - 缓存服务
- `processors/email.processor.ts` - 邮件处理器
- `controllers/user.controller.ts` - 用户控制器