Использует ли LinqToSql рекурсивный метод очень плохо для производительности - PullRequest
3 голосов
/ 27 января 2011

У меня есть следующий метод, который получает всех родителей для узла, используя 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 ]

4 голосов
/ 27 января 2011

Таким образом, приведенный выше код представляет собой переход родительской и дочерней иерархии в восходящем (родительском) направлении. Таким образом, в худшем случае это приведет к выполнению 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%, сработает ли это, но идея состоит в том, чтобы использовать деревья выражений / отложенное выполнение, чтобы несколько запросов выполнялись за одну поездку базы данных.

Еще одной идеей было бы написать сохраненный процесс / представление, которое будет возвращать всех родителей (то же самое можно найти в CTE на сервере sql).

EDIT : используется Where вместо First для поиска родительского элемента в вышеприведенном коде, поскольку First, безусловно, будет оцениваться немедленно - (предупреждение: код еще не проверен)

3 голосов
/ 27 января 2011

Это приведет к запросу для каждого родительского узла.

Для этого лучше всего либо написать хранимую процедуру с использованием CTE, либо, если вышеупомянутое, невозможно, выполнить сначала поиск / запрос в ширину.Последнее потребует запроса для каждого уровня, но в результате будет гораздо меньше запросов.

0 голосов
/ 27 января 2011

Это зависит от того, насколько велика ваша иерархия. Если вы знаете , что вам никогда не потребуется повторять это много раз, это не проблема, однако, возможно, быстрее просто загрузить всю таблицу в память, чем отправлять несколько вызовов в базу данных.

0 голосов
/ 27 января 2011

Я не уверен, что вы можете сделать гораздо меньше, это - от всей души - то же самое, но не рекурсивно и, возможно, поэтому немного более эффективно - но проблема всегда будет в запросеродитель.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...