简体   繁体   English

Linq 查询慢,计数。 SQL 查询速度非常快。 我究竟做错了什么?

[英]Linq Query slow with Count. SQL query is very fast. What am I doing wrong?

I have a very basic parent children relationship.我有一个非常基本的亲子关系。 For my main page, I just wanted to get the counts from the children table.对于我的主页,我只想从 children 表中获取计数。

var assignmenTotal = new AssignmentUser
{
    IsSupervisor = supervisor,
    AssignmentTotals = (
        from a in db.Assignments
        where (StartDate.HasValue) 
            ? DbFunctions.TruncateTime(a.CreatedDate) == StartDate 
            : a.IsArchived == false
        orderby a.ID ascending
        join b in db.Adjustments on a.ID equals b.AssignmentID
        group b by new {a.ID,a.UserName,a.Status,a.CreatedDate,a.IsArchived} 
        into g
        select new AssignmentTotals
        {
            ID =  g.Key.ID,
            UserName = g.Key.UserName,
            Status = g.Key.Status,
            ImportedDate = DbFunctions.TruncateTime(g.Key.CreatedDate),
            StartingLocation = (db.Adjustments
                .Where(x => x.AssignmentID == g.Key.ID)
                .OrderBy(x => x.LocationID)
                .Select(x => x.LocationID)
                .FirstOrDefault()),
            EndingLocation = (db.Adjustments.
                Where(x => x.AssignmentID == g.Key.ID)
                .OrderByDescending(x => x.LocationID)
                .Select(x => x.LocationID)
                .FirstOrDefault()),
            TotalLocations = g.Count(x => x.LocationID != null),
            TotalLicensePlates = g.Count(x => x.ExpectedLicensePlateID != null),
            TotalAdjCompleted = g.Count(x => x.Status == "C"),
            IsSameUser = (currUser == g.Key.UserName ? true : false),
            IsArchived = g.Key.IsArchived
        })
        .OrderBy(x => x.ID)
        .ToList()
};

Now total flatten rows are about 1000 and this is taking about 10 seconds to complete.现在展平的总行数约为 1000,这大约需要 10 秒才能完成。 If I write a SQL Query如果我写一个 SQL 查询

SELECT ID, UserName, Status, b.StartLocation, b.EndLocation, b.TotalLocations, 
       b.TotalLicensePlates, b.TotalLocations 
FROM Assignments a
INNER JOIN(
SELECT AssignmentID,
min(LocationID) as StartLocation, max(LocationID) as EndLocation,
COUNT(CASE WHEN LocationID is NOT NULL THEN 1 ELSE 0 end) AS TotalLocations,
SUM(CASE WHEN ExpectedLicensePlateID IS NOT NULL THEN 1 ELSE 0 END )TotalLicensePlates,
SUM(CASE WHEN Status = 'C' THEN 1 ELSE 0 END )TotalAdjCompleted
FROM dbo.Adjustments
group by AssignmentID
) b on (a.ID = b.AssignmentID)
WHERE convert(date,a.CreatedDate) ='04/23/2021'

This takes less than a second to complete.这需要不到一秒钟的时间来完成。

I think my problem is in the linq COUNT part.我认为我的问题出在 linq COUNT 部分。 I have tried doing a subquery but is still slow.我试过做一个子查询,但仍然很慢。 I think the problem is that the linq query is bringing all the data to client and doing all the work in the client instead of having the server doing all the work?我认为问题在于 linq 查询将所有数据带到客户端并在客户端完成所有工作,而不是让服务器完成所有工作?

Is there a better way to do this?有一个更好的方法吗?

Edit: I'm using Entity Framework and when I checked the SQL profiler, the SQL send is very long and complicated.编辑:我正在使用实体框架,当我检查 SQL 分析器时,SQL 发送非常长且复杂。

Entity Framework (just like any other programmatic Object Relational Mapper) get worse performance and efficient the more complex your request is.实体框架(就像任何其他程序化 Object 关系映射器一样)的性能和效率越差,您的请求越复杂。

So, options:所以,选项:

  1. Deal with it.处理它。 Eh, it's not the best.嗯,这不是最好的。 Clearly it's going to be slow, but if it work, it works.显然它会很慢,但如果它起作用,它就会起作用。
  2. Use Raw SQL Queries in EF EF6 / core .在 EF EF6 / core中使用 Raw SQL 查询。
  3. Use a different ORM, but you'd need to evaluate those yourself to find the pros and cons.使用不同的 ORM,但您需要自己评估这些以找出优缺点。
  4. Forgo SQL in c# entirely and use Stored Procedures, View, Functions, and other SQL objects to keep SQL queries in the database. Forgo SQL in c# entirely and use Stored Procedures, View, Functions, and other SQL objects to keep SQL queries in the database. (thanks Antonín Lejsek ) (感谢Antonín Lejsek

Problem here, that you have written non equivalent LiNQ Query.这里的问题是,您编写了非等效的 LiNQ 查询。 There is no optimal prediction what to do with FirstOrDefault in projection.在投影中没有最佳预测如何处理FirstOrDefault It creates additional OUTER APPLY joins which is slow.它会创建额外的 OUTER APPLY 连接,但速度很慢。

Rewrite your query to be closer to the SQL as possible:重写您的查询,使其尽可能接近 SQL:

 var query =
    from a in db.Assignments
    where (StartDate.HasValue) 
        ? DbFunctions.TruncateTime(a.CreatedDate) == StartDate 
        : a.IsArchived == false
    orderby a.ID ascending
    join b in db.Adjustments on a.ID equals b.AssignmentID
    group b by new {a.ID,a.UserName,a.Status,a.CreatedDate,a.IsArchived} 
    into g
    select new AssignmentTotals
    {
        ID =  g.Key.ID,
        UserName = g.Key.UserName,
        Status = g.Key.Status,
        ImportedDate = DbFunctions.TruncateTime(g.Key.CreatedDate),
        StartingLocation = g.Min(x => x.LocationID)
        EndingLocation = g.Max(x => x.LocationID),
        TotalLocations = g.Count(x => x.LocationID != null),
        TotalLicensePlates = g.Count(x => x.ExpectedLicensePlateID != null),
        TotalAdjCompleted = g.Count(x => x.Status == "C"),
        IsSameUser = (currUser == g.Key.UserName ? true : false),
        IsArchived = g.Key.IsArchived
    };

var totals = query
        .OrderBy(x => x.ID)
        .ToList();

var assignmenTotal = new AssignmentUser
{
    IsSupervisor = supervisor,
    AssignmentTotals = totals
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM