Co jest lepsze: wielu łączy warunki lub wiele warunków, w których?

13

Próbuję porównać dwa zapytania:

Zapytanie 1:

SELECT a,b,c,d,e
FROM tableA
LEFT JOIN tableB
ON tableA.a=tableB.a
WHERE tableA.b=tableB.b AND tableA.c=tableB.c  AND tableA.d=tableB.d  AND tableA.e=tableB.e 

Zapytanie 2:

SELECT a,b,c,d,e
FROM tableA
LEFT JOIN tableB
ON tableA.a=tableB.a AND tableA.b=tableB.b AND tableA.c=tableB.c  AND tableA.d=tableB.d  
WHERE tableA.e=tableB.e 

Czy mam rację twierdząc, że te dwa zapytania dają takie same wyniki?

Ponadto, czy słuszne jest stwierdzenie, że pierwsze zapytanie buduje większą tabelę, dla której można wykonać większy WHEREwarunek; podczas gdy w drugim przypadku mamy mniejszą tabelę, do której WHEREnastępnie stosuje się prosty .

Zakładając, że wyniki są takie same, które zapytanie powinno być preferowane? Czy jest oczywisty problem z wydajnością?

Geoff
źródło
3
Nie, nie masz racji mówiąc. Byłoby, gdyby to był INNER JOIN, ale z LEFT JOINtym zwróci inne wyniki. Zasadniczo, warunki, które zostały dodane na WHEREna drugim zapytaniu są konwersja JOINna zasadzieINNER JOIN
Lamak
Ach ok. Śledzę to, co mówisz. Jeśli dokonam edycji, aby INNER JOINmoje pytania dotyczące wydajności pozostały ważne?
Geoff,
4
W przypadku ŁĄCZNIKÓW WEWNĘTRZNYCH nie powinno być żadnej różnicy w wydajności. To powiedziawszy, dla czytelności i właściwego wyrażenia intencji, powinieneś użyć kryteriów łączenia w ONi kryteriów filtrowania w WHERE.
Aaron Bertrand
@ypercube racja, brakowało mi tego warunku.
Lamak

Odpowiedzi:

10

Jeśli uznamy, że używasz INNER JOINzamiast LEFT JOIN(co wydaje się twoim zamiarem), te dwa zapytania są funkcjonalnie równoważne. Optymalizatory zapytań sprawdzą i ocenią kryteria zawarte w WHEREklauzuli i FROMklauzuli oraz wezmą pod uwagę wszystkie te czynniki przy tworzeniu planów zapytań w celu osiągnięcia najbardziej wydajnego planu wykonania. Jeśli zrobimy EXPLAINna obu instrukcjach, otrzymamy ten sam wynik:

Zapytanie 1 :

EXPLAIN
SELECT 
  tableA.ColA
  ,tableA.ColB
  ,tableA.ColC
  ,tableA.ColD
  ,tableA.ColE
FROM tableA
  JOIN tableB ON tableA.ColA=tableB.ColA
WHERE 
  tableA.ColB=tableB.ColB 
  AND tableA.ColC=tableB.ColC 
  AND tableA.ColD=tableB.ColD  
  AND tableA.ColE=tableB.ColE

[Wyniki] :

| ID | SELECT_TYPE |  TABLE | TYPE | POSSIBLE_KEYS |    KEY | KEY_LEN |    REF | ROWS |                          EXTRA |
------------------------------------------------------------------------------------------------------------------------
|  1 |      SIMPLE | tableA |  ALL |        (null) | (null) |  (null) | (null) |    1 |                                |
|  1 |      SIMPLE | tableB |  ALL |        (null) | (null) |  (null) | (null) |    1 | Using where; Using join buffer |

Zapytanie 2 :

EXPLAIN
SELECT 
  tableA.ColA
  ,tableA.ColB
  ,tableA.ColC
  ,tableA.ColD
  ,tableA.ColE
FROM tableA
  JOIN tableB ON tableA.ColA=tableB.ColA
  AND tableA.ColB=tableB.ColB 
  AND tableA.ColC=tableB.ColC 
  AND tableA.ColD=tableB.ColD  
WHERE
  tableA.ColE=tableB.ColE

[Wyniki] :

| ID | SELECT_TYPE |  TABLE | TYPE | POSSIBLE_KEYS |    KEY | KEY_LEN |    REF | ROWS |                          EXTRA |
------------------------------------------------------------------------------------------------------------------------
|  1 |      SIMPLE | tableA |  ALL |        (null) | (null) |  (null) | (null) |    1 |                                |
|  1 |      SIMPLE | tableB |  ALL |        (null) | (null) |  (null) | (null) |    1 | Using where; Using join buffer |

Możesz przejrzeć pełne informacje za pomocą poniższych linków. Stworzyłem również przykład SQL 2008, abyś mógł porównać działanie dwóch silników (co jest takie samo):

Przykład zapytania MySQL

Przykład zapytania w SQL 2008 (upewnij się, że „wyświetlasz plan wykonania” dla obu wyników)

Mike Fal
źródło
Dziękujemy za szczegółowe rozwiązanie. Próbowałem INNER JOINzamiast LEFT JOINi uzyskuję ten sam wynik w dziesiątej części czasu. Chyba wiem, dlaczego otrzymuję taką samą moc wyjściową, ale dlaczego miałbym INNER JOINlepszą wydajność?
Geoff,
4
Podobnie LEFT JOINjak sprzężenie zewnętrzne, nie może ograniczyć zestawu danych po pełnej stronie powrotu zestawu i spróbuje pobrać wszystkie wiersze z tej tabeli (w tym przypadku TableA). Jeśli używasz INNER JOIN, może wykorzystać te kryteria w obu tabelach i ograniczyć zestaw danych, zapewniając w ten sposób szybszy zwrot.
Mike Fal