2011-01-27 8 views
3

LinqToSqlを使用してノードのすべての親ノードを取得する方法がありますが、パフォーマンスにどれだけ悪いのか分かりません。 NodeTableから再帰的メソッドでLinqToSqlを使用していると、パフォーマンスが非常に悪いです。

public partial class Node 
{ 
    public List<Node> GetAllParents(IEnumerable<Node> records) 
    { 
     if (this.ParentID == 0) 
     { 
      // Reach the parent, so create the instance of the collection and brake recursive. 
      return new List<Node>(); 
     } 

     var parent = records.First(p => p.ID == ParentID); 

     // create a collection from one item to concat it with the all parents. 
     IEnumerable<Node> lst = new Node[] { parent }; 

     lst = lst.Concat(parent.GetAllParents(records)); 

     return lst.ToList(); 
    } 
} 

が、それは良いです!またはそれを改善するための任意のアイデア!

ありがとうございました。

+0

このLINQ to Objectsはありませんか? – Ani

+0

@Ani:いいえ、LinqToSQLによって生成された生成クラスの部分クラスです。 – Homam

+0

実行時に実際に時間がかかり過ぎるまで、パフォーマンスを心配する必要はありません。この瞬間、ほとんどの時間をどこから失うかを見ることができます。 – Shimrod

答えて

4

したがって、上記のコードは、親子階層を上(親)方向に歩いています。したがって、最悪の場合、nの階層深度のデータベースへのn個のクエリを作成します。私はこの方法を変更することにより、遅延実行をしようとするあなたを示唆している少しのような

public IEnumerable<Node> GetAllParents(IEnumerable<Node> records) 
{ 
     if (this.ParentID == 0) 
     { 
      // Reach the parent, so create the instance of the collection and brake recursive. 
      return new List<Node>(); 
     } 

     var parent = records.Where(p => p.ID == ParentID); 
     var parents = parent.Concat(parent.GetAllParents(records)); 

     return parent; 
} 

私はそれが仕事だろうが、複数のクエリを単一のデータベース内で発射されるように、アイデアは式ツリー/繰延実行を利用することである場合には100%を確認していません旅行。

もう1つのアイデアは、すべての親を返すストアドプロシージャ/ビューを作成することです(SQL ServerのCTEを参照)。

EDIT:ファーストは確かにすぐに評価されますので、上記のコードでは、親を見つけるためのWhereの代わりFirstを使用し - (警告:まだ未テストコード)

+0

私の方法はデータベース上で多くの往復をしますか?私は確信していませんが、私はそれを呼び出すときにすべてのレコードをメソッドに渡すので、いいえと思います。再帰を開始する前にすべてのレコードを取得する必要がありますか?あるいは 'IEnumerable 'の代わりに 'List 'を使う必要がありますか? – Homam

+0

@ John-89、ここでは入力が評価されていないということです。そのような場合、 'First'メソッドを呼び出すと、データベースクエリは要求された親レコードを取得します。 'ToList'は、実際のオブジェクトをフェッチするようにデータベースクエリを強制します。すべてのレコード( 'List ')をメソッドに渡すことができます。その場合はデータベースクエリはありませんが、パフォーマンスはレコード数に依存します。たとえば、100,000人の従業員の大組織の中にある従業員の組織レポーティング階層(10-15レベル)が必要な場合、10-15を選択するのではなく、100000人の従業員をすべて取得する必要があります。 – VinayC

3

この結果、1つの親ノードごとにクエリが実行されます。

これに最も近いのは、CTEを使用してストアドプロシージャを作成することでも、前述したことができない場合は、幅広い最初の検索/クエリを実行することです。後者の場合、すべてのレベルのクエリが必要になりますが、全体的にクエリが少なくなります。

0

私ははるかに少ないあなたができることがあることはよく分かりませんこれは私の頭の上から外れていますが、同じですが再帰的ではなく、したがってより効率的ですが、問題は常に親のクエリになります。

List<Node> parentList = new List<Node>(); 
Node current = this; 
while (current.ParentID != 0) 
{ 
    // current = this.Parent; 
    current = records.First(r => r.ID == current.ParentID); 
    parentList.Add(current) 
} 

return parentList; 
0

あなたの階層がどれほど大きくなるかによって異なります。 を知っていれば、何度も繰り返し実行する必要はありませんが、データベースに複数の呼び出しを送信するのではなく、テーブル全体をメモリにロードするほうが簡単です。

関連する問題