2013-06-17 3 views
4

Я пытаюсь переписать процедуру SQL в Linq, все прошло хорошо и отлично работает, пока оно работает маленький набор данных. Я никак не мог найти ответ на это. Вещь есть, у меня есть 3 соединения в запросе, 2 - left joins, а 1 - inner join, все они соединяются друг с другом/как дерево. Ниже вы можете увидеть SQL процедуру:Linq-to-SQL левое соединение слева join/несколько левых объединений в одном выражении Linq-to-SQL

SELECT ... 
    FROM sprawa s (NOLOCK) 
     LEFT JOIN strona st (NOLOCK) on s.ident = st.id_sprawy 
     INNER JOIN stan_szczegoly ss (NOLOCK) on s.kod_stanu = ss.kod_stanu 
     LEFT JOIN broni b (NOLOCK) on b.id_strony = st.ident 

То, что я хотел бы спросить у вас есть способ, чтобы перевести это Linq. Теперь у меня есть это:

var queryOne = from s in db.sprawa 
       join st in db.strona on s.ident equals st.id_sprawy into tmp1 
       from st2 in tmp1.DefaultIfEmpty() 
       join ss in db.stan_szczegoly on s.kod_stanu equals ss.kod_stanu 
       join b in db.broni on st2.ident equals b.id_strony into tmp2 
       from b2 in tmp2.DefaultIfEmpty() 
       select new { }; 

Кажется хорошо, но при проверке с SQL Profiler, запрос, который отправляется в базу данных выглядит следующим образом:

SELECT ... FROM [dbo].[sprawa] AS [Extent1] 
      LEFT OUTER JOIN [dbo].[strona] AS [Extent2] 
       ON [Extent1].[ident] = [Extent2].[id_sprawy]  
      INNER JOIN [dbo].[stan_szczegoly] AS [Extent3] 
       ON [Extent1].[kod_stanu] = [Extent3].[kod_stanu]  
      INNER JOIN [dbo].[broni] AS [Extent4] 
       ON ([Extent2].[ident] = [Extent4].[id_strony]) OR 
       (([Extent2].[ident] IS NULL) AND ([Extent4].[id_strony] IS NULL)) 

Как вы можете видеть оба запроса SQL являются немного по-другому , Эффект один и тот же, но последний работает несравненно медленнее (менее секунды до более 30 минут). Там также есть union, но это не должно быть проблемой. Если меня попросят, я вложу код для него.

Буду благодарен за любые советы, как улучшить производительность моего заявления Linq или как написать его таким образом, чтобы он был правильно переведен.

+0

Если zakreslenie - это переменная, вы можете разбить свой оператор в двух разных выражениях с помощью if (zakreslenie == - 1), затем {} else {} '. Операторы OR имеют тенденцию быть плохой для производительности, поэтому это может помочь. И если вы действительно не можете превратить сложный оператор linq в хорошо выполняющийся запрос, возможно, стоит подумать о вызове хранимой процедуры? – Sam

+0

Плохо хранимая процедура тоже не работает. Кроме того, как я уже говорил, проблема связана с объединениями, все остальное работает отлично (переделано с помощью переведенного sql-запроса) – Rufix

+1

Если вы не можете сделать быстрый SQL-запрос для выполнения того, что хотите, вы не сможете быстро выполнить оператор linq или. Оптимизация slq-запроса для скорости намного проще, чем оптимизация оператора linq, хотя, поскольку с помощью sql вы можете получить план объяснения, чтобы выяснить, что замедляет его. Это может быть OR в вашем запросе, который вызывает снижение вашей скорости, но это может быть и отсутствие правильной индексации. – Sam

ответ

1

Я думаю, я нашел решение:

var queryOne = from s in db.sprawa 
       join st in db.strona on s.ident equals st.id_sprawy into tmp1 
       where tmp1.Any() 
       from st2 in tmp1.DefaultIfEmpty() 
       join ss in db.stan_szczegoly on s.kod_stanu equals ss.kod_stanu 
       join b in db.broni on st2.ident equals b.id_strony into tmp2 
       where tmp2.Any() 
       from b2 in tmp2.DefaultIfEmpty() 
       select new { }; 

Другими словами where table.Any() после каждого into table заявления. Это не делает перевод лучше, но ускорил время выполнения от почти 30 минут (!) До 5 секунд.

Это необходимо использовать осторожно, потому что оно МОЖЕТ привести к потере некоторых записей в наборе результатов.

+1

Это не имеет никакого смысла. Если вы заставляете tmp1 и tmp2 иметь какие-либо записи для квалификации, то у вас есть соединение, а не левое соединение. –

+0

Ну, это сработало, запрос работает одинаково и быстрее. Я не уверен, но я думаю, что tmp.Любой() не будет принуждать любую запись к квалификации, она будет квалифицировать записи, которые существуют. Вы хотите, чтобы я показал вам SQL-запрос результата? – Rufix

Смежные вопросы