SortedSet <T>Содержит запрос Linq - PullRequest
1 голос
/ 05 августа 2010

У меня есть очень простой SortedSet с методом CompareTo, который сортирует на основе двух полей класса.Как это используется, эта коллекция может стать довольно большой (миллион + объектов) и растет и растет со временем.Я использовал простой метод Contains, чтобы определить, существует ли уже новое значение в коллекции ...

В качестве учебного упражнения я делаю некоторые тесты, используя Linq (который я довольно новичок) для достижениятот же эффект, и я уверен, что есть некоторое понимание Linq, которого мне не хватает, потому что я не могу удаленно приблизиться к той же производительности, и мне было интересно, может ли какой-нибудь гуру Linq дать мне указатель на то, что можно сделать, чтобы ускорить его.

Итак ... У объекта есть CompareTo, которое выглядит примерно так:

public int CompareTo(EntityHistoryChange other)
{
    int recordIdComp = Recordid.CompareTo(other.Recordid);
    int tableIdComp = Tablename.CompareTo(other.Tablename);

    if (recordIdComp == 0 && tableIdComp == 0)
        return 0;
    else if (recordIdComp != 0)
        return recordIdComp;
    else
        return tableIdComp;
}

Соответствующий запрос Linq для простого списка:

var handledChange = from thisChange in handledChanges
                    where thisChange.Recordid == recordId 
                      && thisChange.Tablename == tableName
                    select thisChange;

Полагаю, результатыМеня не должно удивлять ...

Linq Lookup on 18772 rows: 46 ms
SortSet Lookup on 18772 rows: 3 ms

Так что вопрос - что такое эквивалентный механизм LINQ?

Ответы [ 3 ]

2 голосов
/ 05 августа 2010

Linq никогда не будет таким быстрым, поскольку этот объект, который видит Linq, не SortedSet, а IEnumerable<T>, у которого нет семантики, кроме «Дайте мне список объектов». Вы вообще не пользуетесь Сет'нессом.

По какому ключу сортируется SortedSet<T>? Разве это не просто поиск через SortedSet.Contains, тогда вы можете проверить имя таблицы?

0 голосов
/ 06 августа 2010

LINQ не предназначен для замены использования правильных структур данных для данного задания. Это просто облегчает работу с этими структурами данных. Если вы храните данные в базе данных SQL, вы все равно должны использовать интеллектуальные индексы в вашей БД для повышения производительности. Аналогично, с LINQ to Objects вам необходимо использовать структуры данных, такие как SortedSet<T>, где это уместно.

Итак, ответ на ваш вопрос: LINQ-запрос для имитации метода Contains будет:

var exists = handledChanges.Any(c => c.Recordid = recordId && c.Tablename == tableName);

Но если вы используете LINQ to Objects, это никогда не приведет к такой же производительности, как при использовании метода Contains в структуре данных, которая специально предназначена для быстрого поиска. Если вы используете LINQ to SQL или LINQ to Entities, это обеспечит оптимизированный SQL-запрос, который может выполняться очень быстро.

Кстати, если ваша цель - ускорить поиск в коллекции в памяти, вы можете рассмотреть возможность использования HashSet с пользовательским IEqualityComparer. Его метод Contains должен занимать столько же времени для коллекции миллионов объектов, сколько и для коллекции из 10.

0 голосов
/ 05 августа 2010

Многие операторы LINQ проверяют наличие интерфейсов за пределами IEnumerable<T> и используют их.

Например, Count будет проверять наличие ICollection<T> и использовать его свойство Count вместо перебора всей коллекции.Единственный способ увидеть это (вне эталонных тестов) - посмотреть на IL (или использовать Refector), и, конечно, реализация может измениться с новой версией .NET (включая SP).Например, в .NET r.5 Count не проверял ICollection, но в 4.

...