2013-03-07 5 views
5

Mam zapytanie, które trwa 2,5 sekundy przy użyciu opcji FULL JOIN i 40 sekund przy użyciu INNER, RIGHT lub LEFT JOIN.W jaki sposób INNER/RIGHT/LEFT JOIN mogą być 14 razy wolniejsze niż FULL JOIN?

Oto zapytanie. Podzapytowanie (wykonane dwukrotnie) zajmuje tylko 1,3 sekundy.

SELECT T1.[time], T1.Total, T1.rn, T2.[time], T2.Total, T2.rn 
FROM 
(
select [time], MAX(ComputedValue) as Total, row_number() over (order by [time]) as rn 
FROM 
(
    select SUBSTRING(CONVERT(CHAR(10), IntervalStartTime, 108), 0, 6) as [time], ComputedValue 
    from LoadTestTransactionSample 
    where LoadTestRunId=285 
    and CounterName='Total Transactions' 
    and TransactionName='Export' 
) foo 
group by [time] 
) T1 
_____ JOIN 
(
select [time], MAX(ComputedValue) as Total, row_number() over (order by [time]) as rn 
FROM 
(
    select SUBSTRING(CONVERT(CHAR(10), IntervalStartTime, 108), 0, 6) as [time], ComputedValue 
    from LoadTestTransactionSample 
    where LoadTestRunId=285 
    and CounterName='Total Transactions' 
    and TransactionName='Export' 
) foo 
group by [time] 
) T2 
ON T1.rn = T2.rn - 1 

select SUBSTRING bit jest po prostu coraz HH: MM ciąg z DateTime. LoadTestTransactionSample to właściwie WIDOK, który łączy się z 8 stołami. (FYI baza danych to magazyn wyników testu obciążenia programu Visual Studio). Oto jego (istotne) kolumny:

LoadTestRunId INT NOT NULL 
CounterName NVARCHAR(255) NOT NULL 
TransactionName NVARCHAR(64) NOT NULL 
IntervalStartTime DATETIME NOT NULL 
IntervalEndTime DATETIME NOT NULL 
ComputedValue REAL 

pełnego złączenia powraca dodatkowy niepotrzebny wiersz, więc trzeba zrobić RIGHT JOIN, aby uzyskać właściwą odpowiedź.

nie jestem naprawdę szuka rozwiązania (mam jedną: pre-fetch podzapytania w tabeli zmiennej używać SQL Server 2012 analityczną funkcję "LGD, dzięki @ a1ex07), po prostu pewne zrozumienie jako do , co może spowodować ekstremalną różnicę w wydajności między tymi typami łączenia.


EDIT: Oto slow right join query plan i fast full join query plan. Są za duże, by opublikować zrzut ekranu.

EDIT 2: Właściwie plany zapytań mają prawo JOIN na poziomie 45% i pełnego złączenia w 55%, co okazuje się być kompletnie nieprawdziwe (w rzeczywistości kończy się gorzej niż 99%/1%). Sądzę, że oznacza to, że muszę polegać na faktycznych statystykach wykonania.

EDIT 3: Statystyki dla powolnego RIGHT JOIN:

(40 row(s) affected) 
Table 'LoadTestPerformanceCounterCategory'. Scan count 0, logical reads 37556, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounter'. Scan count 0, logical reads 176464, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestScenario'. Scan count 0, logical reads 176464, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestCase'. Scan count 0, logical reads 176464, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'WebLoadTestTransaction'. Scan count 0, logical reads 13411100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounterInstance'. Scan count 0, logical reads 36563718, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounterSample'. Scan count 19721, logical reads 269657, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestRunInterval'. Scan count 41, logical reads 205, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 36754 ms, elapsed time = 36763 ms. 

Statystyki dla szybkiego pełnego złączenia:

(41 row(s) affected) 
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounterCategory'. Scan count 0, logical reads 1832, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounter'. Scan count 0, logical reads 8608, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestScenario'. Scan count 0, logical reads 8608, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestCase'. Scan count 0, logical reads 8608, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'WebLoadTestTransaction'. Scan count 0, logical reads 654200, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounterInstance'. Scan count 0, logical reads 1783596, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestPerformanceCounterSample'. Scan count 962, logical reads 13154, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'LoadTestRunInterval'. Scan count 2, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 1950 ms, elapsed time = 1944 ms. 

prawo JOIN robi znacznie więcej odsłon i więcej skanów niż FULL JOIN, mimo podobno podobnego planu zapytania.

Czy Stół roboczy (w PEŁNYM DOŁĄCZU) podpowiedź? Czy to stolik tymczasowy?

Czy to sugeruje, że optymalizator zapytań jest zepsuty?

+1

Ustaw statystyki planu zapytania/wyświetlacz dalej i widzieć. Bez skryptów DDL, aby móc replikować swój schemat i dane, każda odpowiedź jest w zasadzie zgadywana. Czy te wartości wydajności różnią się w pierwszym zapytaniu, podobnie jak w przypadku kolejnych zapytań? To oznacza, że ​​angażujesz się w pamięć podręczną. – Heather

+1

Myślę, że Heather chce poprosić o ich wykonanie 1-2-3-4, a następnie 4-3-2-1 i porównać –

+1

Ponadto, każda wersja zapytania generuje własny plan zapytania w pamięci podręcznej, a te nie są koniecznie odświeżony w tym samym czasie. Może to prowadzić do sporadycznych problemów z wydajnością. –

Odpowiedz

2

OK, okazuje się, że odpowiedź brzmi: złe statystyki db. Bardzo źle. Jak w, nigdy nie był aktualizowany.

exec sp_updatestats; FTW.

[chowa głowę ze wstydu]

1

To jest Plan wykonania podobnych zapytań. Stoły są bardzo małe.

Execution Plan

Query 1:

  • Używa INNER JOIN.
  • Plan wykonania wygląda na mniejszy.
  • Jednak trwa to 62% całkowitego czasu.

Query 2:

  • Używa FULL JOIN.
  • Plan wykonania wygląda na duży.
  • Jednak trwa to 38% całkowitego czasu.

Powód: INNER JOIN w moim przypadku jest użycie HASH meczu. A FULL JOIN używa NESTED LOOP. Decyduje o tym optymalizator SQL, z którego należy korzystać z fizycznego sprzężenia (możemy jednak użyć innego sprzężenia fizycznego). Sprawdź swój plan wykonania, to pomoże.

+1

Możesz skorzystać z niektórych indeksów na tych tabelach. – DaveShaw

+0

@DaveShaw: Tak, to prawda. –

+0

@RaviSingh: co dziwne, wygląda na to, że plany zapytań nie pasują do wykonania! Zobacz moje edycje - plan przewiduje stosunek 45%/55% dla PRAWEGO JOIN vs PEŁNA JOIN, ale wykonanie zakończyło się 99%/1%. – agentnega