How do I speed up this EntityFramework query? The profiler tells me that most of the time is spent in od.Order
with ~5000 calls.
var orderDetails = context.OrderDetails.ToList();
foreach (OrderDetail od in orderDetails)
{
var date = od.Order.date;
if (!trPerDay.ContainsKey(date))
{
trPerDay.Add(date, od.quantity);
}
else
{
trPerDay[date] = od.quantity;
}
}
Order
property is defined like this:
[MetadataType(typeof(OrderDetailMetaData))]
public partial class OrderDetail
{
public int orderID { get; set; }
public string productID { get; set; }
public int quantity { get; set; }
public bool upgraded { get; set; }
public virtual Order Order { get; set; }
public virtual Product Product { get; set; }
}
CodePudding user response:
What you posted loads the entire OrderDetails
table in a single query, from a single thread. Then it tries to lazily load each order which results in a separate call to the database.
It's far faster to let the database do the calculations and only load the final results.
In this case it seems the loop is trying to calculate the total order quantity per order date. The SQL query that produces this would be something like :
SELECT Date,SUM(details.Quantity)
FROM Orders inner join OrderDetails details
on Orders.ID=details.OrderID
GROUP BY Orders.Date
The equivalent in LINQ can be :
var query=context.OrderDetails
.GroupBy(d=>d.Order.Date)
.Select(g=>new {
Date=g.Key,
Total=g.Sum(dt=>dt.Quantity)
});
var totals=await query.ToListAsync();
or
var totals=await query.ToDictionaryAsync(t=>t.Date,t=>t.Quantity)
In both cases, a GROUP BY query will be generated that calculates the totals by date.
This assumes that Date
is what it says - a date. Either a date
-typed field in the database, or a datetime
without a time component. If it's actually a Date Time, the query will have to be adjusted to use only the date part. Luckily, EF Core maps DateTime.Date
to the equivalent SQL function call:
var query=context.OrderDetails
.GroupBy(d=>d.Order.Date)
.Select(g=>new {
Date=g.Key,
Total=g.Sum(dt=>dt.Quantity)
});