2011-01-27 43 views
3

我有以下方法,它使用LinqToSql獲取節點的所有父節點,但我不知道它對性能有多糟。在遞歸方法中使用LinqToSql非常糟糕的性能

從NodeTable:

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到對象嗎? – Ani 2011-01-27 10:13:39

+0

@Ani:不,它位於由LinqToSQL創建的生成的部分類中。 – Homam 2011-01-27 10:14:54

回答

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%肯定它是否會工作,但想法是利用表達式目錄樹/延期執行,以便多個查詢單個數據庫內發射行程。

還有一個想法是編寫一個存儲過程/視圖,它將返回所有父級(在SQL Server中查看CTE的相同內容)。

編輯:用於Where代替First在上面的代碼中發現父母因爲首先肯定會立即評估 - (警告:仍未經測試的代碼)

3

這將導致對每個單個父節點的查詢。

最好的辦法是使用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

這取決於您的層次結構可能有多大。如果你知道它永遠不會需要多次遞歸不是一個問題,但是它可能會更快地將整個表加載到內存中,而不是多次調用數據庫。

相關問題