2011-09-08 6 views
5

odkryłem, że w niektórych przypadkach zapytania jakserwer SQL przyłączyć vs kwestii wydajności Podzapytanie

select 
    usertable.userid, 
    (select top 1 name from nametable where userid = usertable.userid) as name 
from usertable 
where active = 1 

bierze rząd wielkości dłużej, aby zakończyć w SS2008R2 niż równowartość zapytania z join

select 
    usertable.userid, 
    nametable.name 
from usertable 
left join nametable on nametable.userid = usertable.userid 
where usertable.active = 1 

gdzie zarówno tabele są indeksowane i mają ponad 100 tys. wierszy. Co ciekawe, wkładając górną klauzuli do oryginalnego zapytania czyni go wykonać na równi z kwerendy dołączyć:

select 
    top (select count(*) from usertable where active = 1) usertable.userid, 
    (select top 1 name from nametable where userid = usertable.userid) as name 
from usertable 
where active = 1 

Czy ktoś ma jakiś pomysł, dlaczego pierwotne zapytanie wykonuje tak źle?

+3

FYI podczas diagnozowania problemów z wydajnością należy zawsze uzyskać plan wykonania kwerendy. – Justin

+0

Jeśli masz dostęp do Safari Books Online, spójrz na "Inside Microsoft® SQL Server 2005: Tuning zapytań i optymalizacja - rozdział 3" lub Inny dobry link http://blogs.msdn.com/b/craigfr/archive/2006 /09/27/774107.aspx –

Odpowiedz

3

Cóż, zapytania są różne - chyba że kolumna userid jest kluczem podstawowym lub ma ograniczenie unikalności, a drugie zapytanie może zwrócić więcej wierszy niż pierwszego.

Mimo to, przy założeniu że identyfikator użytkownika jest kluczem podstawowym/wyjątkowy spróbuj usunąć TOP 1 część pierwszego podzapytaniu:

select 
    usertable.userid, 
    (select name from nametable where userid = usertable.userid) as name 
from usertable 
where active = 1 
+0

To całkowicie załatwiło sprawę. Miałem go tam jako środek ostrożności, aby uniknąć błędów w czasie wykonywania, ponieważ zapytanie jest generowane w locie. Teraz muszę się dowiedzieć, czy mogę bezpiecznie usunąć to z zasady. –

2

Jest to skorelowane podkwerendy, co oznacza, że ​​musi wykonać jeden raz na wiersz powrotu kwerendy zewnętrznej, ponieważ odwołuje się do pola w kwerendzie zewnętrznej.

A JOIN uruchamia się raz dla całego zestawu wyników i zostaje scalony. Podzapytanie uruchamia zapytanie zewnętrzne, a następnie dla każdego zwróconego wiersza ponownie uruchamia ono podzapytanie.

+1

Nie sądzę, aby było tak z SQL Server. – JeffO

+2

@Jeff - wtedy się mylisz. – JNK

1

Oryginalne zapytanie wykona sub select tyle razy, ile jest wierszy, a tym samym słabej wydajności.

Po uzyskaniu JOIN uzyskujesz cały zestaw wyników naraz.