2016-11-17 3 views
4

Я использую Linq для сущностей, чтобы запросить базу данных, чтобы получить список int для дальнейшей обработки. У меня есть два пути, чтобы получить список, как показано ниже:Производительность: .Join vs .Contains - Linq to Entities

Первый вопрос:

List<int> lstBizIds = new List<int>() { 1, 2, 3, 4, 5 }; 
List<int> lstProjectIds = context.Projects.Where(x => lstBizIds.Contains(x.businessId)).Select(x => x.projectId).ToList(); 

Во-вторых:

List<int> lstBizIds = new List<int>() { 1, 2, 3, 4, 5 }; 
List<int> lstProjectIds = context.Projects.Join(lstBizIds, p => p.businessId, u => u, (p, u) => p.projectId).ToList(); 

Теперь мой вопрос, который один из методов выше лучшая производительность? Также влияет ли это на производительность, если первый список i.e lstBizIds растет в размерах? Предложите мне другие способы реализации, если это сокращение производительности.

+0

Вы уверены, что сначала первый вариант? Выполняется ли запрос и дает результат? – Sefe

+0

Да, определенно это сработает. –

+0

Извините, я имел в виду второй вариант. Во всяком случае, я полагаю, вы успешно пробовали оба. – Sefe

ответ

1

Выполнение соединения довольно эффективно, потому что, когда условие фактически выполняет декартово произведение всех таблиц, затем фильтрует строки, которые удовлетворяют условию. Это означает, что условие Where оценивается для каждой комбинации строк (n1 * n2 * n3 * n4)

Оператор Join берет строки из первых таблиц, а затем берет только строки с соответствующим ключом из второй таблицы, то только строки с соответствующим ключом из третьей таблицы и т. д. Во-вторых, содержащиеся будут работать итеративно, делая его медленнее, чем соединение.

+0

Да, я также обнаружил, что в одной из ссылок на переполнение стека: http: // stackoverflow.com/questions/5551264/why-is-linq-join-so-much-faster-than-linking-with-where Но также найдено противоречивое объяснение здесь: http://stackoverflow.com/questions/32650224/innerjoin-vs -contains-which-is-fast –

+1

Это относится к LINQ to Objects, но вопрос о LINQ to Entities. –

+0

Метод Объединения использует индексы для объединения двух результирующих наборов, но использует механизм комбинации, который замедляет работу. The Join намного быстрее, потому что он знает, как объединить, чтобы уменьшить результат до соответствующих комбинаций. Когда вы используете Where, чтобы указать отношение, он должен создать все возможное сочетание, которое в конечном итоге сделает это медленнее. Надеюсь, это ответит на ваш вопрос. –

2

Вы должны пойти с Contains, потому что EF может создавать более эффективный запрос.

Это будет SQL присоединиться:

SELECT Id 
FROM Projects 
INNER JOIN (VALUES (1), (2), (3), (4), (5)) AS Data(Item) ON Projects.UserId = Data.Item 

Это будет SQL Содержит:

SELECT Id 
FROM Projects 
WHERE UserId IN (1, 2, 3, 4, 5, 6) 

IN является более эффективным, чем JOIN потому, что СУБД может налюбоваться после первого матча IN; JOIN всегда заканчивается, даже после первого матча.

Возможно, вам также захочется проверить, какие запросы действительно отправляются в БД. Вы всегда должны сравнивать SQL, а не код LINQ (очевидно).

+2

Вы правы для сгенерированного SQL (хотя 'join' для SqlServer выглядит по-другому) +1. Но не для которого, если эффективнее, - это действительно зависит от оптимизатора плана запросов к базе данных. Большинство современных оптимизаторов запросов будут создавать один и тот же план выполнения. –

+3

Обратите внимание, что Содержит ОЧЕНЬ медленно в Entity Framework для относительно больших наборов (скажем, 1000 единиц). Это происходит медленно по внутренним причинам, а не потому, что сгенерированный запрос медленный. Поэтому из-за этого - лучше никогда не использовать Содержит на больших наборах. – Evk

+0

Напротив, я недавно провел тест, сравнивающий Contains and Join, Contains лучше, чем Join во всех отношениях. Содержит быстрее, чем Join в терминах выполнения запроса. А также быстрее с точки зрения генерации SQL. Выполнение соединения с элементами 100K даст вам исключение StackOverflow во время генерации SQL. –

0


Я выбираю первый, поскольку он не увеличивает память компьютера.
Если вы используете оба массива для сравнения условий, выберите один из них.

0

Я просто потратил немало времени, пытаясь найти, что вызвало ошибку переполнения стека в программе с помощью нескольких простых запросов LINQ, обращающихся к базе данных среднего размера.

для ICollection с элементами ~ 10k на одной стороне и sql-таблицей с другой стороны, одно изменение от «join» до «Contains» исправило ошибку переполнения стека.

кажется, что, несмотря на сравнительную производительность, Содержит более безопасный выбор.