【问题标题】:ASP.Net Core API response takes too much timeASP.Net Core API 响应需要太多时间
【发布时间】:2020-04-27 14:48:41
【问题描述】:

我有一个包含 9000 行和 97 列的 SQL 数据库表。它的主键有 2 列:ColorName。您可以看到简化的表格以更好地成像:

我有一个 ASP.NET Core API 监听 URL api/color/{colorName},它读取表格以获取颜色信息。目前我有 3 种颜色,每种颜色大约 3000 行。

这需要太多时间。它在 2383 毫秒内读取表格并在 14 毫秒内映射到 DTO。之后我立即将 DTO 返回给消费者,但不知何故 API 需要 4135.422 毫秒。我不明白为什么。我想我应该花 2407.863 毫秒,但事实并非如此。它需要将近 2 倍的时间。

您可以在下面看到我的代码和日志。您知道如何提高响应时间吗?

我使用 Entity Framework Core 3.1、AutoMapper 和 ASP.NET Core 3.1。

服务:

public async Task<IEnumerable<ColorDTO>> GetColors(string requestedColor)
{
    var watch = System.Diagnostics.Stopwatch.StartNew();
    var colors = await _dbContext.Colors.Where(color => color.color == requestedColor).ToListAsync();
    watch.Stop();
    _logger.LogError("Color of:{requestedColor} Reading takes:{elapsedMs}", requestedColor, watch.ElapsedMilliseconds);


    var watch2 = System.Diagnostics.Stopwatch.StartNew();
    var colorDtos = _mapper.Map<IEnumerable<ColorDTO>>(colors);
    watch2.Stop();
    _logger.LogError("Color of:{requestedColor} Mapping takes:{elapsedMs}", requestedColor, watch2.ElapsedMilliseconds);

    return colorDtos;
}

控制器:

public async Task<ActionResult<IEnumerable<ColorDTO>>> GetBlocksOfPanel(string requestedColor)
{
    return Ok(await _colorService.GetColors(requestedColor));
}

还有日志:

2020-04-27 15:21:54.8793||0HLVAKLTJO59T:00000003|MyProject.Api.Services.IColorService|INF|Color of Purple Reading takes:2383ms
2020-04-27 15:21:54.8994||0HLVAKLTJO59T:00000003|MyProject.Api.Services.IColorService|INF|Color of Purple Mapping takes:14ms
2020-04-27 15:21:54.9032||0HLVAKLTJO59T:00000003|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|INF|Executed action method MyProject.Api.Web.Controllers.ColorsController.GetColors (MyProject.Api.Web), returned result Microsoft.AspNetCore.Mvc.OkObjectResult in 2407.863ms.
2020-04-27 15:21:54.9081||0HLVAKLTJO59T:00000003|Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor|INF|Executing ObjectResult, writing value of type 'System.Collections.Generic.List`1[[MyProject.Api.Contracts.Dtos.ColorDTO, MyProject.Api.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
2020-04-27 15:21:56.4895||0HLVAKLTJO59T:00000003|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|INF|Executed action MyProject.Api.Web.Controllers.ColorsController.GetColors (MyProject.Api.Web) in 4003.8022ms
2020-04-27 15:21:56.4927||0HLVAKLTJO59T:00000003|Microsoft.AspNetCore.Routing.EndpointMiddleware|INF|Executed endpoint 'MyProject.Api.Web.Controllers.ColorsController.GetColors (MyProject.Api.Web)'
2020-04-27 15:21:56.4972||0HLVAKLTJO59T:00000003|Microsoft.AspNetCore.Hosting.Diagnostics|INF|Request finished in 4135.422ms 200 application/json; charset=utf-8

【问题讨论】:

  • 您还需要考虑服务和消费者之间的交易延迟,这可能是额外时间到来的地方。您是否真的需要一次返回所有颜色的行,或者您可以添加 take 和 skip,这样您一次只返回 200 或 X 并且消费者可以从前一点开始回调另一组,如果他们需要
  • 我不知道映射器(Automapper?),但 EF 在您第一次运行它时至少需要额外的时间来编译查询,但只是第一次。第二个请求仍然很慢吗?
  • 它的自动映射器。而且这不是第一次查询,第一次查询需要8秒。而且我真的必须一次发送。
  • 我调查了你的代码。似乎一切正常。您应该打印 SQL 图的屏幕。我确信您的问题与 SQL 方面有关。

标签: c# api asp.net-core


【解决方案1】:

正如@ejwill 在他的评论中提到的,您需要考虑整个操作中的延迟。从数据库获取数据并映射到 DTO 只是请求和响应 API 的往返过程中发生的事情的一部分。

您可以通过那里的一些优化来减少对数据库表的查询时间。您没有指出您正在使用什么数据库,但是基于两个字符串/varchar 值的复合键可能不一定是性能最高的,并且对您正在过滤的值使用索引也可能会有所帮助——有那里的权衡取决于您是针对写入还是针对读取进行优化。话虽如此,无论哪种方式,97 列都不是微不足道的。您是否需要通过 API 查询并返回所有 97 列?分页是一种选择吗?

如果您必须一次返回所有 97 列的所有数据并且您经常查询 API,您还可以考虑使用内存缓存,尤其是在表不经常更改的情况下;您不必每次都往返于数据库,而是将数据的副本保存在内存中,以便可以更快地返回。您可以查看支持分代模型的内存缓存实现,以便在获取新版本时继续提供数据。

https://github.com/jfbosch/recache

【讨论】:

    【解决方案2】:

    结果的序列化可能需要很长时间。

    首先是序列化本身:如果您返回 3k 条记录,则将其序列化为 JSON 或 XML 将花费大量时间。考虑改用更紧凑的二进制格式。

    第二件事是内存和 GC。如果 序列化 数据量超过 85,000 字节,则该数据的内存将在 LOH 上以一个块的形式分配。这可能需要时间。您可能会考虑检查您的 LOH 并查找存储在那里的响应数据。可能的解决方法是使用大块数据进行响应,并使用offsetposition 进行分页。

    您可以轻松检查序列化是否会导致性能问题:保留对 DB 的调用,但只返回 100-200 行而不是整个结果,或者返回较少的对象字段(例如,仅 3 个)。应该减少时间。

    【讨论】:

      【解决方案3】:

      您的问题与 SQL 方面有关。您应该检查列的索引并在执行计划状态下运行查询以找到瓶颈。另外,为了提高性能,我建议在异步状态下重写代码。

      【讨论】:

      • Alireza joon,它已经在使用异步方法了。你读过代码吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-28
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多