这是一个关于SPEED的问题 - 有很多记录需要访问。
有关问题的基本信息
例如,我们将在数据库中有三个表。
关系: Order-ProductInOrder是一对多(订单可以包含许多产品) ProductInOrder-产品是一对一的(订单中的产品由一种产品代表)
public class Order {
public bool Processed { get; set; }
// this determines whether the order has been processed
// - orders that have do not go through this again
public int OrderID { get; set; } //PK
public decimal TotalCost{ get; set; }
public List<ProductInOrder> ProductsInOrder;
// from one-to-many relationship with ProductInOrder
// the rest is irrelevant and will not be included here
}
//represents an product in an order - an order can have many products
public class ProductInOrder {
public int PIOD { get; set; } //PK
public int Quantity{ get; set; }
public int OrderID { get; set; }//FK
public Order TheOrder { get; set; }
// from one-to-many relationship with Order
public int ProductID { get; set; } //FK
public Product TheProduct{ get; set; }
//from one-to-one relationship with Product
}
//information about a product goes here
public class Product {
public int ProductID { get; set; } //PK
public decimal UnitPrice { get; set; } //the cost per item
// the rest is irrelevant to this question
}
假设我们收到一批订单,我们需要在这些订单中应用折扣并查找订单的总价。这适用于10,000到100,000多个订单。这种方式的工作方式是,如果订单有5个或更多的产品,其中每个产品的成本是100美元,我们将对总价格给予10%的折扣。
我尝试过什么
我尝试了以下内容:
//this part gets the product in order with over 5 items
List<Order> discountedOrders = orderRepo
.Where(p => p.Processed == false)
.ToList();
List<ProductInOrder> discountedProducts = discountedOrders
.SelectMany(p => p.ProductsInOrder)
.Where(q => q.Quantity >=5 )
.ToList();
discountedProducts = discountedProducts
.Where(p => p.Product.UnitPrice >= 100.00)
.ToList();
discountOrders = discountedOrders
.Where(p => discountProducts.Any(q => q.OrderID == p.OrderID))
.ToList();
这非常慢并且需要永远运行,当我对它运行集成测试时,测试似乎超时了。我想知道是否有更快的方法来做到这一点。
答案 0 :(得分:2)
尝试不在每次查询后调用ToList
。
当您在查询上调用ToList
时,它将被执行并且对象将从内存中的数据库加载。基于第一个查询的结果的任何后续查询都在列表的内存中执行,而不是直接在数据库中执行。你想要做的是在数据库上执行整个查询,只返回那些验证你所有条件的结果。
var discountedOrders = orderRepo
.Where(p=>p.Processed == false);
var discountedProducts = discountedOrders
.SelectMany(p=>p.ProductsInOrder)
.Where(q=>q.Quantity >=5);
discountedProducts = discountedProducts
.Where(p=>p.Product.UnitPrice >= 100.00);
discountOrders = discountedOrders
.Where(p=>discountProducts.Any(q=>q.OrderID == p.OrderID));
答案 1 :(得分:1)
嗯,首先,结合这些调用会加快一些速度。试试这个:
discountOrders = orderRepo.Where(p=>p.Processed == false && p.SelectMany(q=>q.ProductsInOrder).Where(r=>r.Quantity >=5 && r.Product.UnitPrice >= 100.00 && r.OrderID == p.OrderId).Count() > 0).ToList();
请注意,这未经过测试。我希望我的逻辑正确 - 我想我做到了,但如果我没有,请告诉我。
答案 2 :(得分:1)
与@PhillipSchmidt相似,你可以合理化你的Linq
var discountEligibleOrders =
allOrders
.Where(order => !order.Processed
&& order
.ProductsInOrder
.Any(pio => pio.TheProduct.UnitPrice >= 100M
&& pio.Quantity >= 5))
删除所有那些讨厌的ToList
语句是一个很好的开始,因为你可能会将数据库中可能显着更大的集合提升到你的应用程序。让数据库完成工作。
获取每个订单及其价格(假设折扣价格为0.9 *上市价格):
var ordersAndPrices =
allOrders
.Where(order => !order.Processed)
.Select(order => new {
order,
isDiscounted = order
.ProductsInOrder
.Any(pio => pio.TheProduct.UnitPrice >= 100M
&& pio.Quantity >= 5)
})
.Select(x => new {
order = x.order,
price = x.order
.ProductsInOrder
.Sum(p=> p.Quantity
* p.TheProduct.UnitPrice
* (x.isDiscounted ? 0.9M : 1M))});
答案 3 :(得分:0)
我知道你有一个已接受的答案,但请尝试这个以增加速度 - PLINQ(并行LINQ)这将采用4000列表,如果你有4个核心,它将在每个核心上过滤1000,然后整理结果。 / p>
List<Order> orders = new List<Order>();
var parallelQuery = (from o in orders.AsParallel()
where !o.Processed
select o.ProductsInOrder.Where(x => x.Quantity >= 5 &&
x.TheProduct.UnitPrice >= 100.00 &&
orders.Any(x => x.OrderID = x.OrderID));
请看这里:
在许多情况下,通过更有效地使用主机上的所有可用内核,PLINQ可以显着提高LINQ to Objects查询的速度。这种提高的性能为桌面带来了高性能计算能力
答案 4 :(得分:-1)
将其移动到1个查询中,但实际上您应该将其移动到SSIS包或sql作业中。您可以轻松地将其设置为在不到一秒钟内运行的存储过程。