简体   繁体   中英

How do I speed up this EF query?

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; }
}

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)
                  });

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.

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