I have a very basic parent children relationship. For my main page, I just wanted to get the counts from the children table.
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. If I write a SQL Query
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. 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?
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.
Entity Framework (just like any other programmatic Object Relational Mapper) get worse performance and efficient the more complex your request is.
So, options:
Problem here, that you have written non equivalent LiNQ Query. There is no optimal prediction what to do with FirstOrDefault
in projection. It creates additional OUTER APPLY joins which is slow.
Rewrite your query to be closer to the SQL as possible:
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
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.