2013-05-02 20 views
6

Pracuję na następujące pytania:SQL sprzężenia wewnętrznego vs podzapytaniu

Query 1: SELECT * From TabA INNER JOIN TabB on TabA.Id=TabB.Id 
Query 2: SELECT * From TabA WHERE Id in (SELECT Id FROM TabB) 
Query 3: SELECT TabA.* From TabA INNER JOIN TabB on TabA.Id=TabB.Id 

I zbadanie tych zapytań SQL Server Profiler i znaleźć kilka interesujących faktów.

  • Zapytanie 1 odbywa 2.312 sekund
  • Zapytanie 2 trwa 0,811 sekund
  • Zapytanie 3 ma 0,944 sekund

taba 48716 wierszy

Tabb 62719 wierszy

Zasadniczo pytam, dlaczego Query 1 zajmuje dużo czasu, a nie zapytania 3. Już wiem, że "sub-zapytanie" jest wolniejsze niż wewnętrzne sprzężenie, ale tutaj Query 2 jest najszybsze; czemu?

+1

Dlaczego istnieje znacznik 'C# '? To nie ma znaczenia. –

+6

Czy uruchomiłeś te pomiary wiele razy? Wydajność kwerend w dużym stopniu zależy od tego, czy tabele są ładowane do pamięci podręcznej strony. –

+3

należy zachować ostrożność przy użyciu pamięci podręcznej. Czysz to po każdym zapytaniu? –

Odpowiedz

3

Gdybym musiał zgadywać, powiedziałbym, że to dlatego, że zapytanie 1 pobiera dane z obu tabel. Zapytania 2 i 3 (w tym samym czasie) pobierają tylko dane dla TabA.

Jeden sposób można sprawdzić to wykonując następujące czynności:

SET STATISTICS TIME ON 
SET STATISTICS IO ON 

Kiedy wpadłem

SELECT * FROM sys.objects 

widziałem następujące wyniki.

SQL Server parse and compile time: 
    CPU time = 0 ms, elapsed time = 104 ms. 

(242 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 'sysschobjs'. Scan count 1, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'syssingleobjrefs'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
Table 'syspalnames'. Scan count 1, logical reads 2, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 866 ms. 

Możesz rzucić okiem na # skanów, odczytów logicznych i fizycznych odczytów dla każdego zapytania. Fizyczne odczyty oczywiście trwają znacznie dłużej i reprezentują odczyt z dysku do pamięci podręcznej. Jeśli wszystkie twoje odczyty są logiczne, to twoja tabela jest całkowicie w pamięci podręcznej.

Byłbym skłonny się założyć, jeśli spojrzeć widać dużo bardziej logiczne czyta na Tabb na zapytania 1 niż na 2 i 3.

EDIT:

Tak z ciekawości zrobiłem niektóre testy i blogowane wyniki here.

+0

Nice blog post Kenneth. –

1

Po prostu dlatego, że SQL nie musi wykonywać JOIN. Właśnie wykonuje dwa kwerendy i tylko jeden z nich ma klauzulę WHERE.

Muszę przyznać, że nie spodziewałem się TAK dużej różnicy.

+0

Nice! ale subprocesy powinny być wolniejsze niż wewnętrzne zapytania łączenia. [Referencja] (http://stackoverflow.com/questions/141278/subqueries-vs-joins) –

+0

Tak mówi podręcznik, ale ma to więcej sensu, im mniej dzieje się za kulisami, tym szybciej otrzymujesz wyniki. Zastanawiam się, co by się stało, gdyby utworzono widok z zapytania JOIN i przetestowano jego wydajność. Nawiasem mówiąc, widoki lub procedury przechowywane są znacznie szybsze niż zwykłe zapytania JOIN, ponieważ plan wykonania jest przechowywany. –

2

Zapytanie 1:
To zapytanie powoduje zwrócenie wierszy ze wszystkich wierszy zarówno w TabA, jak i TabB, więc indeks zakrycia dla obu tabel wymaga uwzględnienia wszystkich wierszy z każdej tabeli. Aby zobaczyć dokładnie, co się dzieje, należy spojrzeć na plan zapytania.

Query 2 & Zapytanie 3:
Wracasz wszystkie wiersze z Taba i trzeba tylko indeks dla kolumny Identyfikator Tabb. Zgaduję, że różnica tutaj ma coś wspólnego ze statystyką tabeli, ale (po raz kolejny) musielibyśmy zobaczyć plan zapytań, aby dokładnie wiedzieć, co się dzieje.

Powiązane problemy