Как оптимально объединить две коллекции в LINQ с несколькими условиями для MS SQL Server - PullRequest
0 голосов
/ 08 июля 2019

Как вы знаете, в Интернете приведены примеры для двух коллекций, которые связаны в соответствии с несколькими условиями:

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 секунд: enter image description here

2) для INNER JOIN-UNION в среднем время выполнения составляет менее 1 секунды: enter image description here

Поправка . После всех тестов оказалось, что AND дает INNER JOIN, а OR дает CROSS JOIN

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...