首页 > 解决方案 > ASP.NET Core 3.1 实体框架存在查询持续时间

问题描述

我正在尝试在 ASP.NET Core 3.1 MVC 应用程序中分析数据库优先的 EF SQL 查询,这似乎有点浪费时间。

在使用秒表并努力获得我想要的粒度之后,我安装了 MiniProfiler(如果你没有它,那就太棒了,得到它)。

简而言之,该函数将接收一个以逗号分隔的零件 ID 字符串,并返回一个工单基本 ID 的字符串 [];

string[] part_array = part.Split(',');
string[] base_id_array = { };

using (MiniProfiler.Current.Step("TestDB"))
{
    using (DB_Access.AccessContext db_context = new DB_Access.AccessContext())
    {
        var query = from a in db_context.WorkOrder.AsNoTracking()
                    where part_array.Contains(a.User2)
                    select new
                    {
                        a.BaseId
                    };

        if (query != null)
        {
            if (query.Any())
            {                       
                foreach (var item in query)
                {
                    Array.Resize(ref base_id_array, base_id_array.Length + 1);
                    base_id_array[base_id_array.GetUpperBound(0)] = item.BaseId;
                }
            }
        }
    }
}

MiniProfiler 显示以下内容;

在此处输入图像描述

所以首先 EF 执行一个 EXIST 查询,耗时 147.7ms

然后 EF 关闭连接,重新打开,执行实际的 SELECT 查询,只需要 40.4ms

我想问题是三方面的;

  1. 为什么 EF 执行 EXIST 查询?
  2. 为什么查询要花这么长时间?
  3. 为什么连接在同一个 using 语句中被关闭和重新打开?

标签: c#sql-serverasp.net-coreentity-framework-core

解决方案


为什么 EF 执行 EXIST 查询?

因为您在代码中有下一行:

if (query.Any())

这将导致您的第一个查询。首先实现查询并使用结果:

var queryResults = (from a in db_context.WorkOrder.AsNoTracking()
                where part_array.Contains(a.User2)
                select new
                {
                    a.BaseId
                })
                .ToList();
foreach (var item in queryResults)
{
    Array.Resize(ref base_id_array, base_id_array.Length + 1);
    base_id_array[base_id_array.GetUpperBound(0)] = item.BaseId;
}

您不需要null检查(因为您将本地分配给一个变量,ToList如果在数据库中没有找到结果,则返回空变量)并且Anyforeach将为您处理)。

为什么查询要花这么长时间?

似乎 MiniProfiler 没有说查询在数据库端需要多长时间,它说需要多长时间ExecuteReader。我将假设这是一些运行一次的测试代码,因此由于 JIT 编译,它可能需要很长时间(比选择时间更长),并且后续调用需要更少的时间,因为 JIT 编译已经为它执行了。但我建议使用数据库探查器检查查询。


推荐阅读