Как вы знаете, в Интернете приведены примеры для двух коллекций, которые связаны в соответствии с несколькими условиями:
var query = from e1 in seq1
from e2 in seq2
where (e1.Key1 == e2.Key1)
&& (e1.Key2 == e2.Key2)
select new {Data1 = e1.Data, Data2 = e2.Data};
Однако при работе с MS SQL Server аналогичная конструкция LINQ превратится в CROSS JOIN в T-SQL. Это легко увидеть, если преобразовать результат в тип ObjectQuery, а затем вызвать метод ToTraceString:
string sql = (query as ObjectQuery) .ToTraceString ();
Console.WriteLine (sql);
Тогда для условия А при соединении двух коллекций лучше использовать кортеж во внутреннем соединении вместо декартового произведения из-из LINQ:
var query = from e1 in seq1
join e2 in seq2
on new {e1.Key1, e1.Key2} equals new {e2.Key1, e2.Key2}
select new {Data1 = e1.Data, Data2 = e2.Data};
Однако, как это сделать для условия ИЛИ:
var query = from e1 in seq1
from e2 in seq2
where (e1.Key1 == e2.Key1)
|| (e1.Key2 == e2.Key2)
select new {Data1 = e1.Data, Data2 = e2.Data};
Однако при внутреннем соединении слева от ключевого слова equals не может быть e2, а справа - e1, тогда вы можете написать следующее:
var query = (from e1 in seq1
join e2 in seq2
on e1.Key1 equals e2.Key1
select new {Data1 = e1.Data, Data2 = e2.Data}).Union (from e1 in seq1
join e2 in seq2
on e1.Key2 equals e2.Key2
select new {Data1 = e1.Data, Data2 = e2.Data});
Да, запросы обычно оказываются неэквивалентными, учитывая, что могут быть возвращены полные дубликаты строк. Однако в реальной жизни полные дубликаты строк не нужны, и они пытаются от них избавиться.
Можно ли написать последний запрос более оптимально как по производительности, так и по восприятию кода?
Примеры плохих решений для запросов LINQ к MS SQL Server:
http://qaru.site/questions/2444051/greater-than-with-multiple-conditions-in-linq-join
а также
http://qaru.site/questions/231459/linq-left-join-on-multiple-or-conditions
Планы:
1) для CROSS JOIN среднее время выполнения составляет 195 секунд:
2) для INNER JOIN-UNION в среднем время выполнения составляет менее 1 секунды:
Поправка . После всех тестов оказалось, что AND дает INNER JOIN, а OR дает CROSS JOIN