用缓存功能解决.NET程序访问数据库的性能问题

摘要

针对.NET项目中数据库查询性能问题,本文提出多维度优化方案:

1)使用SQL Server Profiler等工具分析慢查询;

2)通过添加索引、优化SQL语句提升查询效率;

3)引入缓存机制(Redis/MemoryCache)减轻数据库压力;

4)采用异步操作提高并发能力。

文中给出了C#实现示例,展示如何通过IMemoryCache实现带过期策略的数据缓存,有效提升系统响应速度。

问题描述

在一些.NET项目中,会遇到数据库查询性能问题,影响了整体系统的响应时间。

解决方案和思路

分析查询性能

使用数据库的性能分析工具(如SQL Server Profiler 或MySQL 的EXPLAIN语句)来分析慢查询。

优化查询:

根据分析结果,优化SQL 查询。例如,添加适当的索引,避免使用不必要的子查询,使用

分页等。

缓存:

对于频繁访问且不经常变化的数据,使用缓存(如Redis、MemoryCache)来减少数据库的压力。

异步操作

使用异步数据库操作(如async 和await)来提高系统的并发处理能力。

实现

csharp 复制代码
 var builder = WebApplication.CreateBuilder(args);
 builder.Services.AddMemoryCache();
 
  var mySQLConfig = builder.Configuration.GetSection("MySQL").Get<MySQLConfig>();
  var connectionString = mySQLConfig!.ConnectionString;
  builder.Services.AddDbContext<MySQLContext>(dbContextOptions =>
  {
      dbContextOptions
      .UseMySql(connectionString,
          ServerVersion.AutoDetect(connectionString),
          mysqlOptions =>
          {
              mysqlOptions.EnableStringComparisonTranslations();
              mysqlOptions.EnableRetryOnFailure(
                          maxRetryCount: mySQLConfig.MaxRetryCount,
                          maxRetryDelay: TimeSpan.FromSeconds(mySQLConfig.MaxRetryDelaySeconds),
                          errorNumbersToAdd: null
              );
          })
      .UseLazyLoadingProxies();
  });
        
 var app = builder.Build();
 ServiceLocator.Provider = app.Services;
 
 app.Run();
csharp 复制代码
public static class ServiceLocator
{
    public static IServiceProvider Provider { get; set; } = default!;
}
csharp 复制代码
public static class DbExecuter
{
    public static async Task<TResult> ExecuteAsync<TResult>(Func<MySQLContext, Task<TResult>> action)
    {
        using var scope = ServiceLocator.Provider.CreateScope();
        using var db = scope.ServiceProvider.GetRequiredService<MySQLContext>();
        return await action(db);
    }
}
csharp 复制代码
 private static readonly IMemoryCache cache = ServiceLocator.Provider.GetRequiredService<IMemoryCache>();
 private static TimeSpan DEFAULT_SLIDING_EXPIRATION = TimeSpan.FromHours(3);
 private static TimeSpan DEFAULT_ABSOLUTE_EXPIRATION = TimeSpan.FromHours(24);
 private static TimeSpan NULL_DATA_ABSOLUTE_EXPIRATION = TimeSpan.FromMinutes(5);
 
 public static async Task<List<Product>?> GetProductsByProductTypeAsync(ProductTypeEnum call)
    {
        var cacheKey = KEY_PRODUCTS_BY_PRODUCT_TYPE + call.ToString();
        return await cache.GetOrCreateAsync(cacheKey, async entry =>
        {
            entry.SlidingExpiration = DEFAULT_SLIDING_EXPIRATION;
            var data = await DbExecuter.ExecuteAsync(async db =>
            {
                return await db.Products
                                 .Where(x => x.Type == call)
                                 .OrderBy(x => x.Sort)
                                 .ToListAsync();
            });
            entry.AbsoluteExpirationRelativeToNow =
                data == null ? NULL_DATA_ABSOLUTE_EXPIRATION : DEFAULT_ABSOLUTE_EXPIRATION;
            return data;
        });
    }
相关推荐
jiayou642 天前
KingbaseES 实战:深度解析数据库对象访问权限管理
数据库
李广坤3 天前
MySQL 大表字段变更实践(改名 + 改类型 + 改长度)
数据库
用户298698530143 天前
程序员效率工具:Spire.Doc如何助你一键搞定Word表格排版
后端·c#·.net
牧马人win3 天前
SmartDapper.Repository
.net
爱可生开源社区4 天前
2026 年,优秀的 DBA 需要具备哪些素质?
数据库·人工智能·dba
随逸1774 天前
《从零搭建NestJS项目》
数据库·typescript
mudtools4 天前
搭建一套.net下能落地的飞书考勤系统
后端·c#·.net
玩泥巴的4 天前
搭建一套.net下能落地的飞书考勤系统
c#·.net·二次开发·飞书
加号34 天前
windows系统下mysql多源数据库同步部署
数据库·windows·mysql