2009-07-24 7 views
15

Jako przykład, chcę uzyskać listę wszystkich elementów z pewnymi znacznikami zastosowanymi do nich. Mogę zrobić jedną z następujących czynności:Wydajność SQL: GDZIE W podaplikowaniu vs. JOIN, a następnie GRUPA

SELECT Item.ID, Item.Name 
FROM Item 
WHERE Item.ID IN (
    SELECT ItemTag.ItemID 
    FROM ItemTag 
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55) 

Albo

SELECT Item.ID, Item.Name 
FROM Item 
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
GROUP BY Item.ID, Item.Name 

Albo coś zupełnie innego.

Ogólnie (zakładając, że istnieje ogólna zasada), jakie jest bardziej skuteczne podejście?

+0

@Larsenal: możesz zamienić 'LEFT JOIN' na' INNER JOIN' w twoim drugim zapytaniu, wyniki będą takie same. 'LEFT JOIN' zwróci' NULL's dla wierszy w 'ItemTag', które nie mają odpowiadającego' Item.ID', a twój warunek "WHERE" odfiltrowuje je. – Quassnoi

Odpowiedz

15
SELECT Item.ID, Item.Name 
FROM Item 
WHERE Item.ID IN (
    SELECT ItemTag.ItemID 
    FROM ItemTag 
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55) 

lub

SELECT Item.ID, Item.Name 
FROM Item 
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
GROUP BY Item.ID 

Twoje drugie zapytanie nie będzie kompilować, ponieważ odwołuje się on Item.Name bez albo grupowania lub agregowania na nim.

Jeśli usuwamy GROUP BY z zapytaniem:

SELECT Item.ID, Item.Name 
FROM Item 
JOIN ItemTag 
ON  ItemTag.ItemID = Item.ID 
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 

są nadal różne zapytania, chyba ItemTag.ItemId jest UNIQUE klucz i oznaczone jako takie.

SQL Server jest w stanie wykryć stan IN na kolumnie UNIQUE i będzie po prostu przekształcić stan IN w JOIN.

Jeśli ItemTag.ItemID nie jest UNIQUE, pierwsze zapytanie użyje pewnego rodzaju algorytmu SEMI JOIN, który jest dość wydajny w SQL Server.

Można trasform drugie zapytanie do JOIN:

SELECT Item.ID, Item.Name 
FROM Item 
JOIN (
     SELECT DISTINCT ItemID 
     FROMT ItemTag 
     WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55 
     ) tags 
ON  tags.ItemID = Item.ID 

ale ten jest odrobinę mniej wydajny niż IN lub EXISTS.

Zobacz artykuł w moim blogu na bardziej szczegółowe porównanie wydajności:

4

Myślę, że zależy to od tego, w jaki sposób obsługuje je optymalizator, może się nawet zdarzyć, że uzyskasz tę samą wydajność. Wyświetl plan wykonania jest tutaj twoim przyjacielem.

1

To prawie niemożliwe (chyba że jesteś jednym z tych szalonych guru DBA), aby powiedzieć, co będzie szybkie, a co nie, bez patrzenia na plan wykonania i/lub przeprowadzania testów warunków skrajnych.

+2

W rzeczywistości łatwo powiedzieć: drugi jest o wiele szybszy. Po prostu odmówi kompilacji w ciągu około nanosekundy. – Quassnoi

+0

Myślę, że naprawiłem to teraz. – Larsenal

+2

@Quassnoi Czy to nie spowolniłoby? Potrzeba nieskończonej ilości czasu, aby zwrócić wynik ... – Kasapo

2
SELECT Item.ID, Item.Name 
... 
GROUP BY Item.ID 

To nie jest prawidłowy T-SQL. Element.Name musi pojawiać się w klauzuli group by lub w funkcji agregującej, takiej jak SUM lub MAX.

+0

Dzięki. Naprawiłem to. – Larsenal

0

run to:

SET SHOWPLAN_ALL ON 

następnie uruchomić każdą wersję zapytania

można sprawdzić, czy wrócą ten sam plan, a jeśli nie patrzeć na TotalSubtreeCost w pierwszym rzędzie każdy i zobaczyć jak się różnią.

0

wydajności zawsze wydaje się głos, ale również usłyszeć „taniej jest kupić sprzęt niż programistów "

Druga wygrywa na występie.

Czasami dobrze jest spojrzeć na SQL i znać cel, ale na to właśnie są komentarze. Pierwsza kwerenda używa drugiej tabeli dla filtra - całkiem prosto do przodu.

Drugi miałby więcej sensu (z punktu widzenia zrozumienia, a nie wydajności), używając wyraźnego zamiast grupowego. Spodziewam się, że niektóre agregaty będą w selekcji, ale nie ma żadnych. Prędkość zabija.

0

Drugi jest bardziej wydajny w MySQL. MySQL ponownie wykona zapytanie w instrukcji IN dla każdego testu warunku WHERE.