Linq To SQL. Как предотвратить использование оператора Apply

У меня есть запрос:

var contactInfos = from person in persons

                    join tempDesiredCar in desiredCars on person.contact_id equals tempDesiredCar.groupEntity_id
                                   into tempDesiredCars
                    from desiredCar in tempDesiredCars.DefaultIfEmpty()
                    select new {name = person.name, car = desiredCar.name};

Этот код переводит на SQL:

SELECT [t1].[name], [t19].[name] AS [car]
FROM [dbo].[Person] AS [t1]
CROSS APPLY ((
        SELECT NULL AS [EMPTY]
        ) AS [t6]
    OUTER APPLY (
        SELECT [t18].[name]
        FROM (
            SELECT [t17].[contact_id], [t17].[name]
            FROM (
                SELECT [t7].[contact_id], [t11].[name]
                FROM [dbo].[DesiredCar] AS [t7]
                INNER JOIN (
                    SELECT MAX([t9].[value]) AS [value]
                    FROM (
                        SELECT [t8].[id] AS [value], [t8].[contact_id]
                        FROM [dbo].[DesiredCar] AS [t8]
                        ) AS [t9]
                    GROUP BY [t9].[contact_id]
                    ) AS [t10] ON ([t7].[id]) = [t10].[value]
                LEFT OUTER JOIN [dbo].[FamilyModel] AS [t11] ON [t11].[id] = [t7].[model]
                WHERE [t7].[model] IS NOT NULL
                UNION
                SELECT [t12].[contact_id], [t16].[name]
                FROM [dbo].[DesiredCar] AS [t12]
                INNER JOIN (
                    SELECT MAX([t14].[value]) AS [value]
                    FROM (
                        SELECT [t13].[id] AS [value], [t13].[contact_id]
                        FROM [dbo].[DesiredCar] AS [t13]
                        ) AS [t14]
                    GROUP BY [t14].[contact_id]
                    ) AS [t15] ON ([t12].[id]) = [t15].[value]
                LEFT OUTER JOIN [dbo].[CarBrand] AS [t16] ON [t16].[id] = [t12].[carBrand_id]
                WHERE [t12].[carBrand_id] IS NOT NULL
                ) AS [t17]
            ) AS [t18]
        where [t1].[contact_id] = [t18].[contact_id]
        ) AS [t19])

That code uses Apply. If replace Apply by Left Join code runs faster in a few times. How to force Linq to generate code using the Left Join?

1
nl ja de
Пожалуйста, покажите нам полный запрос LINQ ...
добавлено автор usr, источник
Также, пожалуйста, разместите графические планы выполнения. Я не вижу причины, по которой APPLY должен привести к другому плану запроса. Вы уверены, что преобразование в LEFT JOIN семантически идентично?
добавлено автор usr, источник
[t18] содержит много предложений, которые не поступают из опубликованной инструкции linq. Можете ли вы опубликовать код, который их генерирует?
добавлено автор Amy B, источник
LINQ to SQL не является «лучшим» способом записи SQL и не заменяет SQL. Легче и быстрее написать такой простой оператор вручную и создать L2S новые объекты из результатов
добавлено автор Panagiotis Kanavos, источник
Это решение делает автоматический рефакторинг недоступным.
добавлено автор Coder, источник
Планирование с применением yadi.sk/d/w9SAcsiu1VDKU
добавлено автор Coder, источник
Планирование с присоединением yadi.sk/d/SbIPPJjf1VDK8 .
добавлено автор Coder, источник

3 ответы

I’ve found the reason why LINQ is using an apply operator. Operands are checking, whether is there dependence from foreign key in that join or there is not. If it's just a table – linq uses "Left Join". LINQ uses "Outer apply" if the subquery contains Group By, Order By with column used in “equals”. Use simple subqueries in LINQ JOIN.

1
добавлено
Я читаю ваш ответ в течение 10 минут, и я до сих пор не понимаю. Я не понимаю ваши предложения, и я не понимаю, что вы подразумеваете под «простыми подзапросами». Я стараюсь избегать оператора «APPLY» сам по разным причинам.
добавлено автор migle, источник

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

Я пытался придумать обходные пути, надеюсь, что они работают:

//project only the needed columns
var contactInfos = from person in persons
                    join tempDesiredCar in
                         desiredCars.Select(x => new { x.groupEntity_id, x.name })
                         on person.contact_id equals tempDesiredCar.groupEntity_id
                         into tempDesiredCars
                    from desiredCar in tempDesiredCars.DefaultIfEmpty()
                    select new { name = person.name, car = desiredCar.name };

//change join to from
var contactInfos = from person in persons
                   from desiredCar in
                         desiredCars.Select(x => new { x.groupEntity_id, x.name })
                                    .Where(x => person.contact_id = x.groupEntity_id)
                                    .DefaultIfEmpty()
                    select new { name = person.name, car = desiredCar.name };

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

0
добавлено
Второе выражение LINQ, LINQ не полностью переводится в SQL.
добавлено автор Coder, источник

Я проверил планы запросов.

В плане применения используются вложенные петли для объединения таблиц. Для каждой записи в таблице Person она считывает каждую запись в таблице DesiredCars. Вам действительно нужно найти нужный автомобиль каждого человека в базе данных? Если нет, попробуйте сначала сначала отфильтровать таблицу Person.

В плане объединения используется Hashmatching для объединения таблиц. Он читает обе таблицы один раз, создавая карту одной таблицы и используя эту карту во второй таблице. Оптимизатор указал несколько рекомендаций по индексу. Эти рекомендации могут помочь обоим планам.

        
          
            
              
                
              
              
                
                
              
            
          
          
            
              
                
              
              
                
                
              
            
          
        
0
добавлено
SqlCom.ru - Стиль жизни SQL
SqlCom.ru - Стиль жизни SQL
908 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только MS SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz). Предложения в @sql_ninja

SQL_Ninja
SQL_Ninja
340 участник(ов)

Правила чата - https://t.me/sqlcom/88269 @sqlcom - основной канал (только SQL) @sql_ninja - второй канал (SQL вопросы начального уровня и свободное общение) @Gopnegbot - Викторина по SQL Server (наберите в привате /quiz)