【问题标题】:High Entity Framework Core execution times高实体框架核心执行时间
【发布时间】:2019-09-04 10:21:14
【问题描述】:

我构建了一个简单的 Asp.Net Core MVC 应用程序,用于在我们的 MSSQL 数据库中显示来自视图的数据。从 SSMS 查询此视图时,执行时间平均约为 100 毫秒。当在我的应用程序中执行相同的查询时,执行时间从 ~800 毫秒到 ~1.5 秒不等。

这是来自控制器的 LINQ:

public IActionResult Index()
{
    var query =
    from p in _context.vWebQuery
    where p.Almachine == "600L"
    orderby p.Aldatsta
    select p;
    return View(query);
}

这是实体类:

namespace BetaKestrel2.Models
{
    public class vWebQuery
    {
        public double Wruntim { get; set; }
        public short Wper { get; set; }
        public double Quantity { get; set; }
        [Column("Total Op TIme")]
        public double? TotalTime { get; set; }
        public string Alwon { get; set; }
        public short Alopnum { get; set; }
        public string Almachine { get; set; }
        public double Alpersta { get; set; }
        [DisplayFormat(DataFormatString = "{0:F2}")]
        public double Allen { get; set; }
        public short Alprevop { get; set; }
        [DisplayFormat(DataFormatString = "{0:d}")]     
        public DateTime Aldatsta { get; set; }
        public string Altimsta { get; set; }
        public string Alstatus { get; set; }
        public short Alperno { get; set; }
        public string Macid { get; set; }
        public string Macdesc { get; set; }
        public string Partid { get; set; }
        public string Partrevisionid { get; set; }
        public string Routingmethod { get; set; }
        public double Wqleft { get; set; }
        public string Wstate { get; set; }
        public string Wdesc { get; set; }
        public string Partdesc { get; set; }
        public string Toolid { get; set; }
        public string Childpartid { get; set; }
        public string msection { get; set; }

    }
}

还有 DbContext:(使用 .Net Core 3.0 实现 .HasNoKey())

public partial class EfacDBContext : DbContext
{
    public EfacDBContext()
    {
    }

    public EfacDBContext(DbContextOptions<EfacDBContext> options)
        : base(options)
    {
    }

    public DbSet<vWebQuery>         vWebQuery { get; set; }
    public DbSet<vGRN>              vGRN      { get; set; }
    public DbSet<vQuotationTracker> vQuotationTracker { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

        modelBuilder.Entity<vWebQuery>(entity =>
        {
            entity.HasNoKey();
            entity.ToTable("vwebquery");
        });

还有一个示例 .cshtml 视图:

@model IEnumerable<BetaKestrel2.Models.vWebQuery>

@{
    ViewData["Title"] = "600L";
    string highlight = "";
}


<h1>Work Centre Plan - @ViewData["Title"]</h1>

<table class="table table-sm table-bordered">
    <thead>
        <tr>
            <th>Works Order</th>
            <th>Part Number</th>
            <th>Description</th>
            <th>Op Number</th>
            <th>Quantity</th>
            <th>Latest Start Date</th>
            <th>Previous Op</th>
            <th>Total Op Time (mins)</th>
            <th>Status</th>
            <th>Qty Left</th>
        </tr>
    </thead>
    <tbody>

    @foreach (var item in Model)
    {

        @if (item.Wstate == "COMP")
        {
            highlight = "background-color: green;";
        }
        else if (item.Alprevop == 0)
        {
            highlight = "background-color: yellow;";
        }
        else
        {
            highlight = "";
        }
        <tr style="@highlight">
            <td>@Html.DisplayFor(modelItem => item.Alwon)</td>
            <td>@Html.DisplayFor(modelItem => item.Partid)</td>
            <td>@Html.DisplayFor(modelItem => item.Partdesc)</td>
            <td>@Html.DisplayFor(modelItem => item.Alopnum)</td>
            <td>@Html.DisplayFor(modelItem => item.Quantity)</td>
            <td>@Html.DisplayFor(modelItem => item.Aldatsta)</td>
            <td>@Html.DisplayFor(modelItem => item.Alprevop)</td>
            <td>@Html.DisplayFor(modelItem => item.TotalTime)</td>
            <td>@Html.DisplayFor(modelItem => item.Wstate)</td>
            <td>@Html.DisplayFor(modelItem => item.Wqleft)</td>
        </tr>
    }
    </tbody>
</table>

EF Core 转换为以下 SQL

SELECT 
    [v].[Aldatsta]
    ,[v].[Allen]
    ,[v].[Almachine]
    ,[v].[Alopnum]
    ,[v].[Alperno]
    ,[v].[Alpersta]
    ,[v].[Alprevop]
    ,[v].[Alstatus]
    ,[v].[Altimsta]
    ,[v].[Alwon]
    ,[v].[Childpartid]
    ,[v].[Macdesc]
    ,[v].[Macid]
    ,[v].[Partdesc]
    ,[v].[Partid]
    ,[v].[Partrevisionid]
    ,[v].[Quantity]
    ,[v].[Routingmethod]
    ,[v].[Toolid]
    ,[v].[Total Op TIme]
    ,[v].[Wdesc]
    ,[v].[Wper]
    ,[v].[Wqleft]
    ,[v].[Wruntim]
    ,[v].[Wstate]
    ,[v].[msection]
FROM [vwebquery] AS [v]
WHERE 
    [v].[Almachine] = N'BENDD'
AND [v].[Almachine] IS NOT NULL
ORDER BY 
    [v].[Aldatsta]

结果:

信息:Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor[4] Executed ViewResult - 视图索引在 1540.6805000000002ms 内执行。

信息:Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2] 在 1541.4348ms 内执行动作 BetaKestrel2.Controllers.BenddController.Index (BetaKestrel2)

信息:Microsoft.AspNetCore.Routing.EndpointMiddleware[1] 执行的端点“BetaKestrel2.Controllers.BenddController.Index (BetaKestrel2)”

信息:Microsoft.AspNetCore.Hosting.Diagnostics[2] 请求在 1541.8467 毫秒内完成 200 text/html;字符集=utf-8

而在 SSMS 中

总执行时间 124 毫秒

我尝试了 AsNoTracking() 并没有什么不同。你最后的评论让我很好奇。查询返回了 291 行,所以我尝试了 .Take(5) 并且执行时间下降到 24ms。 真的只是我的 foreach 循环在视图中的迭代占用了所有时间?

【问题讨论】:

  • 嗯,首先,该数字是您返回响应的执行时间,而不仅仅是运行查询所需的时间。还有许多其他因素可能会减慢响应速度,但我们无法查看您的任何其他代码。
  • 抱歉,我对 OOP 还很陌生,但我仍然对这一切有所了解。为了更清楚,我编辑了我的问题。
  • 看我的回答,你测量的是不一样的东西,只测量查询的执行而不是额外的 OOP 和渲染管道。是的 1v1 会更慢,但不如 EF 给你的有用性那么多。您可能花费的时间可能不到 3 毫秒(可能为什么会更少)
  • 刚刚看到你的更新。具有这么多字段的 291 行(20 个)对于所有 291 个字段应该像 24 毫秒一样快,所以我猜它可能与 DisplayFormat 和 Column 有关,其中一列是否包含大量文本......比如 500加字符..检查字段中数据的大小..
  • wdesc 是 nvarchar(255),但该列中的最高长度是 41 个字符

标签: asp.net-core entity-framework-core


【解决方案1】:

从 SSMS 查询此视图时,执行时间约为 100 毫秒 平均的。在我的应用程序中执行相同的查询时,执行时间 从 ~800ms 到 ~1.5s。

SQL Server 管理工作室 (SSMS)

  • 原始 SQL 没有过头

EF Entityfamework

放这个

var query = 
from p in _context.vWebQuery
where p.Almachine == "BENDD"
orderby p.Aldatsta
select p;

在一个对其计时的块中,循环 3 次并取最后一次。

--create dbContext here. (_context)

--start loop (run 3 times)

    --start timer

var query = ( 
            from p in _context.vWebQuery
           where p.Almachine == "BENDD"
          orderby p.Aldatsta
          select p
        ).Tolist();

    --end timer -this is what you want to compare after the 3 run.
               - yes it will be slower but you could make as non tracking 
               - should be a must fairer comparison.

-- end loop

提示 - 将其置于调试中,在索引上设置断点...将您的查询更改为 ToList(),以便它在该点执行查询,而不是在视图部分中。

测试代码:修改

        for (int i = 0; i <= 3; i++)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            var query = (from p in _context.vWebQuery
                         where p.Almachine == "600L"
                         orderby p.Aldatsta
                         select p
            ).ToList();

            stopwatch.Stop();
            Console.WriteLine(stopwatch.ElapsedMilliseconds);
        }
     .....

【讨论】:

  • 好的,我按照你的建议做了,System.Diagnostics.Stopwatch 时间平均约为 1200 毫秒
  • 以后不要修改别人的答案,而是将其包含在您自己的 Q 或 A 中,反正我修改了那里的内容......因为它没有正确考虑时间
  • 发现 ef 添加 AND [v].[Almachine] IS NOT NULL 很有趣,据我了解它不应该
  • 还要考虑去掉DisplayFormat和Column,还有为什么表没有PK,表上有没有索引。我们感兴趣的是我们正在处理多少行。
猜你喜欢
  • 2013-01-20
  • 2021-07-14
  • 1970-01-01
  • 1970-01-01
  • 2019-08-16
  • 2021-09-30
  • 1970-01-01
  • 2017-04-03
  • 2020-05-10
相关资源
最近更新 更多