AgentSkillsCN

performance

通过异步模式、缓存策略、数据库优化、性能剖析与资源管理,持续优化应用性能。

SKILL.md
--- frontmatter
name: performance
description: 'Optimize application performance through async patterns, caching strategies, database optimization, profiling, and resource management.'

Performance

Purpose: Optimize application speed, throughput, and resource usage for production loads.
Strategy: Profile first, optimize bottlenecks, measure impact.


Quick Wins

OptimizationImpactEffort
Enable Response Compression70-90% size reductionLow
Add Database Indexes10-100x query speedLow
Implement Caching50-99% latency reductionMedium
Use Async/Await5-10x throughputMedium
Fix N+1 Queries10-1000x DB performanceMedium

Profiling

Rule: Always profile before optimizing. Gut feelings lie.

bash
# .NET Profiling
dotnet trace collect --process-id <PID>
dotnet-counters monitor --process-id <PID>

# Memory profiling
dotnet-gcdump collect --process-id <PID>

Tools:

  • Visual Studio Profiler
  • JetBrains dotTrace / dotMemory
  • BenchmarkDotNet (micro-benchmarks)
  • Application Insights (production)

Database Optimization

Fix N+1 Queries

csharp
// ❌ N+1 Query Problem
var users = await _context.Users.ToListAsync();
foreach (var user in users)
{
    var posts = await _context.Posts.Where(p => p.UserId == user.Id).ToListAsync();
}

// ✅ Use Eager Loading
var users = await _context.Users
    .Include(u => u.Posts)
    .ToListAsync();

Add Indexes

csharp
// Migration
modelBuilder.Entity<User>()
    .HasIndex(u => u.Email)
    .IsUnique();

modelBuilder.Entity<Post>()
    .HasIndex(p => new { p.UserId, p.CreatedAt });

Use Projections

csharp
// ❌ Loads entire entity
var users = await _context.Users.ToListAsync();

// ✅ Load only needed fields
var users = await _context.Users
    .Select(u => new { u.Id, u.Name, u.Email })
    .ToListAsync();

Caching

In-Memory Cache

csharp
builder.Services.AddMemoryCache();

public class UserService
{
    private readonly IMemoryCache _cache;
    
    public async Task<User> GetUserAsync(int id)
    {
        return await _cache.GetOrCreateAsync($"user:{id}", async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
            return await _repository.GetByIdAsync(id);
        });
    }
}

Redis Cache

csharp
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost:6379";
    options.InstanceName = "MyApp";
});

public class CachedService
{
    private readonly IDistributedCache _cache;
    
    public async Task<string> GetDataAsync(string key)
    {
        var cached = await _cache.GetStringAsync(key);
        if (cached != null) return cached;
        
        var data = await FetchDataAsync();
        await _cache.SetStringAsync(key, data, new()
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
        });
        return data;
    }
}

HTTP Caching

csharp
[ResponseCache(Duration = 300, VaryByQueryKeys = new[] { "id" })]
public IActionResult GetProduct(int id)
{
    return Ok(_service.GetProduct(id));
}

// Or in middleware
app.UseResponseCaching();

Async/Await

csharp
// ✅ Async all the way
public async Task<IActionResult> GetUsersAsync()
{
    var users = await _service.GetUsersAsync();
    return Ok(users);
}

// ❌ Blocking async (deadlock risk)
public IActionResult GetUsers()
{
    var users = _service.GetUsersAsync().Result; // DON'T
    return Ok(users);
}

// ✅ Parallel async operations
var task1 = _service.GetUserAsync(1);
var task2 = _service.GetOrdersAsync(1);
await Task.WhenAll(task1, task2);

Memory Optimization

Use Span<T> for Large Data

csharp
// ❌ Creates multiple string allocations
public string ProcessData(string data)
{
    return data.Substring(0, 10).ToUpper().Trim();
}

// ✅ Zero allocations with Span
public string ProcessData(ReadOnlySpan<char> data)
{
    var span = data.Slice(0, 10);
    // Process without allocating
    return new string(span);
}

Object Pooling

csharp
using Microsoft.Extensions.ObjectPool;

var pool = ObjectPool.Create<StringBuilder>();

var sb = pool.Get();
try
{
    sb.Append("data");
    return sb.ToString();
}
finally
{
    sb.Clear();
    pool.Return(sb);
}

Response Compression

csharp
builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
    options.Providers.Add<BrotliCompressionProvider>();
    options.Providers.Add<GzipCompressionProvider>();
});

builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.Fastest;
});

app.UseResponseCompression();

Pagination

csharp
public async Task<PagedResult<User>> GetUsersAsync(int page = 1, int pageSize = 20)
{
    var query = _context.Users.AsQueryable();
    var total = await query.CountAsync();
    
    var users = await query
        .Skip((page - 1) * pageSize)
        .Take(pageSize)
        .ToListAsync();
    
    return new PagedResult<User>
    {
        Items = users,
        Page = page,
        PageSize = pageSize,
        TotalCount = total
    };
}

Background Processing

csharp
// Use Hangfire for background jobs
builder.Services.AddHangfire(config =>
    config.UsePostgreSqlStorage(connectionString));
builder.Services.AddHangfireServer();

// Schedule background task
BackgroundJob.Enqueue(() => ProcessLargeFile(fileId));

// Recurring tasks
RecurringJob.AddOrUpdate("cleanup", () => CleanupOldData(), Cron.Daily);

Load Testing

bash
# Apache Bench
ab -n 10000 -c 100 http://localhost:5000/api/users

# k6
k6 run --vus 100 --duration 30s loadtest.js

# Artillery
artillery quick --count 100 --num 1000 http://localhost:5000/api/users

Best Practices

✅ DO

  • Profile before optimizing
  • Cache frequently accessed data
  • Use async/await consistently
  • Add database indexes
  • Paginate large datasets
  • Enable response compression
  • Use connection pooling
  • Monitor performance in production
  • Set cache expiration times
  • Use CDN for static assets

❌ DON'T

  • Optimize without profiling
  • Cache everything indefinitely
  • Mix sync and async code
  • Load entire tables
  • Return unlimited results
  • Block async operations
  • Create new DB connections per request
  • Ignore memory leaks
  • Skip load testing
  • Optimize prematurely

Performance Targets

MetricTargetCritical
API Response Time<200ms<500ms
Database Query<50ms<200ms
Page Load (FCP)<1.5s<3s
Memory Usage<512MB<1GB
CPU Usage<70%<90%

Monitoring

csharp
// Application Insights
builder.Services.AddApplicationInsightsTelemetry();

// Custom metrics
var telemetry = services.GetRequiredService<TelemetryClient>();
telemetry.TrackMetric("ProcessingTime", duration.TotalMilliseconds);
telemetry.TrackDependency("Database", "Query", startTime, duration, success);

See Also: 06-database.md07-scalability.md15-logging-monitoring.md

Last Updated: January 13, 2026