1

SPEED に関する質問です。アクセスするレコードがたくさんあります。

問題に関する基本情報

例として、データベースに 3 つのテーブルがあるとします。

関係: Order-ProductInOrder は 1 対多 (1 つの注文に多くの製品を含めることができます) ProductInOrder- 製品は 1 対 1 (注文内の製品は 1 つの製品で表されます)

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 件を超える注文に適用できます。これが機能する方法は、注文にそれぞれのコストが $100 の製品が 5 つ以上ある場合、合計価格に対して 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();

これは非常に遅く、実行に永遠に時間がかかります。統合テストを実行すると、テストがタイムアウトしたようです。これを行うためのより速い方法があるかどうか疑問に思っていました。

4

5 に答える 5

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));
于 2012-09-06T14:24:37.473 に答える
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();

これはテストされていないことに注意してください。ロジックが正しかったことを願っています。正しかったと思いますが、正しかった場合はお知らせください。

于 2012-09-06T14:32:24.023 に答える
0

受け入れられた回答があることは知っていますが、速度を上げるためにこれを試してください-PLINQ(Parallel LINQ)これは4000のリストを取り、4つのコアがある場合は各コアで1000をフィルタリングしてから結果を照合します。

  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 クエリの速度を大幅に向上させることができます。このパフォーマンスの向上により、高性能のコンピューティング能力がデスクトップにもたらされます

http://msdn.microsoft.com/en-us/library/dd460688.aspx

于 2012-09-06T14:58:56.867 に答える
-1

それを1つのクエリに移動しますが、実際にはこれをSSISパッケージまたはSQLジョブに移動する必要があります. これを、1 秒未満で実行されるストアド プロシージャにするのは簡単です。

于 2012-09-06T14:29:16.870 に答える