在递归方法中使用LinqToSql对性能非常不利

时间:2011-01-27 10:11:42

标签: c# linq performance linq-to-sql

我有以下方法使用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();
    }
}

好吗!或任何提高它的想法!!

感谢。

4 个答案:

答案 0 :(得分: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%确定它是否可行但是想法是利用表达式树/延迟执行,以便在单个数据库行程中触发多个查询。

另一个想法是编写一个存储的proc / view,它将返回所有父节点(在sql server中查看相同的CTE)。

编辑:使用Where代替First在上面的代码中查找父级,因为First肯定会立即进行评估 - (警告:仍然未经测试的代码)

答案 1 :(得分:3)

这将导致查询每个父节点。

最好接近这个也是使用CTE编写存储过程,或者如果上述不可能,请进行广度优先搜索/查询。后者需要对每个级别进行查询,但总体上会产生更少的查询。

答案 2 :(得分: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;

答案 3 :(得分:0)

这取决于您的层次结构可能有多大。如果您知道它永远不需要递归多次不是一个问题,但是将整个表加载到内存而不是向db发送多个调用可能更快。