Соединения LINQ - производительность

Мне любопытно о том, как точно LINQ (не LINQ к SQL) работает, соединения негласно относительно того, как SQL-сервер выполняет соединения.

SQL-сервер прежде, чем выполнить запрос, генерирует План выполнения. Планом выполнения является в основном Дерево выражений на том, чему он верит, лучший способ выполнить запрос. Каждый узел предоставляет информацию о том, сделать ли Вид, Сканирование, Выбор, Соединение, ect.

На узле 'Соединения' в нашем плане выполнения мы видим три возможных алгоритма; Хэширование, Слияние и Соединение Вложенных циклов. SQL-сервер выберет, какой алгоритм к для каждой операции Соединения на основе ожидаемого количества строк во Внутренних и Внешних таблицах, какое соединение мы делаем (некоторые алгоритмы не поддерживают все типы соединений), нужны ли нам данные, заказанные, и вероятно много других факторов.

Алгоритмы соединения:

Соединение Вложенного цикла: Лучше всего для маленьких исходных данных, может быть оптимизирован с заказанной внутренней таблицей.

Слияние: Лучше всего для отсортированных исходных данных средних и крупных исходных данных или вывода, который должен быть заказан.

Хэширование: Лучше всего для средних и крупных исходных данных, может быть параллелизирован для масштабирования линейно.

Запрос LINQ:

DataTable  firstTable, secondTable;

...

var rows = from firstRow in firstTable.AsEnumerable ()
                join secondRow in secondTable.AsEnumerable ()
                    on firstRow.Field<object> (randomObject.Property)
                    equals secondRow.Field<object> (randomObject.Property)
           select new {firstRow, secondRow};

SQL-запрос:

SELECT *
FROM firstTable fT
    INNER JOIN secondTable sT ON fT.Property = sT.Property

SQL-сервер мог бы использовать Соединение Вложенного цикла, если он знает, что существует небольшое количество строк от каждой таблицы, слияние, если он знает, одна из таблиц имеет индекс, и Хэширование, если он знает, существует много строк на любой таблице, и ни у одного нет индекса.

Linq выбирает свой алгоритм для соединений? или это всегда использует тот?

9
задан Meiscooldude 14 June 2010 в 04:03
поделиться

3 ответа

Linq to SQL не отправляет соединение намекает на сервер. Таким образом, производительность соединения с использованием Linq to SQL будет идентична производительности того же соединения, отправленного «напрямую» на сервер (т. Е. С использованием чистого ADO или SQL Server Management Studio) без каких-либо указаний.

Linq to SQL также не разрешает использовать подсказки соединения (насколько мне известно). Поэтому, если вы хотите принудительно выполнить соединение определенного типа, вам придется сделать это с помощью хранимой процедуры или метода Execute [Command | Query] . Но если вы не укажете тип соединения, написав INNER [HASH | LOOP | MERGE] JOIN , тогда SQL Server всегда выбирает тип соединения, который, по его мнению, будет наиболее эффективным - не имеет значения, откуда пришел запрос. из.

Другие поставщики запросов Linq, такие как Entity Framework и NHibernate Linq, будут делать то же самое, что и Linq to SQL. Ни один из них не знает, как вы проиндексировали свою базу данных, и поэтому ни один из них не отправляет подсказки о соединении.

Linq to Objects немного отличается - он (почти?) Всегда выполняет «хеш-соединение» на языке SQL Server.Это потому, что в нем отсутствуют индексы, необходимые для выполнения соединения слиянием, а хэш-соединения обычно более эффективны, чем вложенные циклы, если количество элементов не очень мало. Но для определения количества элементов в IEnumerable в первую очередь может потребоваться полная итерация, поэтому в большинстве случаев быстрее просто предположить худшее и использовать алгоритм хеширования.

4
ответ дан 3 November 2019 в 00:58
поделиться

Сам LINQ не выбирает алгоритмы какого-либо вида, поскольку LINQ, строго говоря, это просто способ выражения запроса в SQL-подобном синтаксисе, который может отображаться на вызовы функций либо IEnumerable, либо IQueryable. LINQ является полностью особенностью языка и не предоставляет функциональности, а только другой способ выражения существующих вызовов функций.

В случае IQueryable выбор наилучшего метода получения результатов полностью зависит от провайдера (например, LINQ to SQL).

В случае LINQ to Objects (использующего IEnumerable) во всех случаях используется простое перечисление (примерно эквивалентное вложенным циклам). Нет глубокой проверки (или даже знания) базовых типов данных для оптимизации запроса.

1
ответ дан 3 November 2019 в 00:58
поделиться

Методы в System.Linq.Enumerable выполняются в порядке их выдачи. Оптимизатора запросов нет.

Многие методы очень ленивы, что позволяет не полностью перечислить источник, помещая .First или .Any или . Возьмите в конце запрос. Это самая простая оптимизация.

В частности, для System.Linq.Enumerable.Join в документации указано, что это хеш-соединение.

Компаратор проверки на равенство по умолчанию, Default, используется для хеширования и сравнения ключей.

Примеры:

//hash join (n+m) Enumerable.Join
from a in theAs
join b in theBs on a.prop equals b.prop

//nestedloop join (n*m)  Enumerable.SelectMany
from a in theAs
from b in theBs
where a.prop == b.prop
6
ответ дан 3 November 2019 в 00:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: