Czy zapytania ANSI JOIN vs. inne niż ANSI JOIN będą działać inaczej?

Mam swoją logikę biznesową w ~7000 liniach procedur składowanych T-SQL, a większość z nich ma składnię next JOIN:

SELECT A.A, B.B, C.C
FROM aaa AS A, bbb AS B, ccc AS C
WHERE
    A.B = B.ID
AND B.C = C.ID
AND C.ID = @param

Czy otrzymam wzrost wydajności, jeśli zamienię takie zapytanie na to:

SELECT A.A, B.B, C.C
FROM aaa AS A
JOIN bbb AS B
   ON A.B = B.ID
JOIN ccc AS C
   ON B.C = C.ID
   AND C.ID = @param
Czy są takie same?
Author: Andy Lester, 2009-10-21

7 answers

Dwa zapytania są takie same, z tym, że drugie to składnia ANSI-92 SQL, a pierwsze to starsza składnia SQL, która nie zawiera klauzuli join. Powinny one produkować dokładnie ten sam wewnętrzny plan zapytań, chociaż możesz chcieć to sprawdzić.

Należy używać składni ANSI-92 z kilku powodów

  • użycie klauzuli JOIN oddziela logika relacji z filtruj logikę (gdzie) i jest w ten sposób czystsze i łatwiejsze do zrozumienia.
  • to nie sprawa z tym konkretnym zapytaniem, ale istnieje kilka okoliczności, w których starsza składnia join (używając +) jest niejednoznaczna, a wyniki zapytania zależą od implementacji - lub zapytanie nie może być rozwiązane w ogóle. Nie występują one w przypadku ANSI-92
  • jest to dobra praktyka, ponieważ większość programistów i dba będzie używać ANSI-92 w dzisiejszych czasach i powinieneś przestrzegać standardu. Z pewnością wszystkie nowoczesne narzędzia zapytań wygenerują ANSI-92.
  • Jak zauważył @gbn, ma tendencję do unikania przypadkowe połączenia krzyżowe.

Sam opierałem się ANSI-92 przez jakiś czas, ponieważ istnieje niewielka zaleta koncepcyjna starej składni, ponieważ łatwiej jest wyobrazić sobie SQL jako masowe kartezjańskie połączenie wszystkich tabel używanych, a następnie operację filtrowania-technikę mentalną, która może być przydatna do uchwycenia tego, co robi zapytanie SQL. Jednak kilka lat temu zdecydowałem, że muszę iść z duchem czasu i po stosunkowo krótkim okresie dostosowawczym teraz zdecydowanie go preferuję - głównie ze względu na pierwszy powód podany powyżej. Jedynym miejscem, w którym należy odejść od składni ANSI-92, lub raczej nie używać tej opcji, jest naturalne połączenia, które są niejawnie niebezpieczne.

 79
Author: Cruachan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-28 13:53:27

Drugi konstrukt jest znany jako "infixed join syntax" w społeczności SQL. Pierwsza konstrukcja AFAIK nie ma powszechnie akceptowanej nazwy, więc nazwijmy ją składnią "old style" inner join.

Zwykłe argumenty idą tak:

Plusy "tradycyjnej" składni: predykaty są fizycznie zgrupowane w klauzuli WHERE w niezależnie od kolejności, która sprawia, że zapytanie ogólnie, a n-ary relacje szczególnie, łatwiejsze do odczytania i zrozumienia (ON klauzule składnia infixed może rozłożyć predykaty, więc musisz szukać wyglądu jednej tabeli lub kolumny na odległość wizualną).

Wady 'tradycyjnej' składni: nie ma błędu parsowania przy pominięciu jednego z predykatów 'join', a wynikiem jest iloczyn kartezjański (znany jako CROSS JOIN w składni infixed) i taki błąd może być trudny do wykrycia i debugowania. Ponadto predykaty "join" i "filtering" są fizycznie zgrupowane razem w klauzuli WHERE, która może sprawiać, że się mylą.

 5
Author: onedaywhen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-19 07:33:04

Ok, wykonują to samo. Zgadzam się. W przeciwieństwie do wielu używam starszej konwencji. To, że SQL-92 jest "łatwiejszy do zrozumienia", jest dyskusyjne. Mając pisane języki programowania przez 40 lat (gulp) wiem, że "łatwy do odczytania" zaczyna się najpierw, przed jakąkolwiek inną konwencją, od "ostrości wzroku" (mylnie stosowany termin tutaj, ale to najlepsza fraza, której mogę użyć). Podczas czytania SQL pierwszą rzeczą, na którą zwracasz uwagę, jest to, jakie tabele są zaangażowane, a następnie która tabela (większość) definiuje ziarno. Wtedy ci zależy o odpowiednich ograniczeniach na danych, a następnie atrybuty wybrane. Podczas gdy SQL-92 głównie oddziela te pomysły, istnieje tak wiele słów hałasu, oko umysłu musi interpretować i radzić sobie z nimi i sprawia, że czytanie SQL wolniej.

SELECT Mgt.attrib_a   AS attrib_a
      ,Sta.attrib_b   AS attrib_b
      ,Stb.attrib_c   AS attrib_c
FROM   Main_Grain_Table  Mgt
      ,Surrounding_TabA  Sta
      ,Surrounding_tabB  Stb
WHERE  Mgt.sta_join_col  = Sta.sta_join_col
AND    Mgt.stb_join_col  = Stb.stb_join_col
AND    Mgt.bus_logic_col = 'TIGHT'
Ostrość Wzroku! Umieść przecinki dla nowych atrybutów przed sobą, co ułatwia komentowanie kodu Użyj konkretnego przypadku dla funkcji i słów kluczowych Użyj konkretnego przypadku dla tabel Użyj konkretnego przypadku dla atrybutów Operatorzy linii pionowych i operacje Zrób pierwszą tabelę (- y) w FROM reprezentują ziarno danych Stwórz pierwsze tabele ograniczeń gdzie być i pozwól specyficznym, ciasnym ograniczeniom unieść się na dno. Wybierz 3-znakowy alias dla wszystkich tabel w bazie danych i używaj go wszędzie tam, gdzie odwołujesz się do tabeli. Powinieneś używać tego aliasu jako prefiksu dla (wielu) indeksów w tej tabeli. 6 z 1,5 tuzina, tak? Może. Ale nawet jeśli używasz konwencji ANSI-92 (tak jak ja i w przypadkach będzie nadal robić) użyj zasad ostrości wzroku, wyrównanie wierzchołków, aby pozwolić umysłowi oko odwrócić się do miejsc, które chcesz zobaczyć i łatwo uniknąć rzeczy (szczególnie słów hałasu), których nie potrzebujesz.
 4
Author: TwoEdgedSword,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-28 12:41:05

Wykonaj oba i sprawdź ich plany zapytań. One powinny być równe.

 3
Author: sisve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-21 06:30:53

Dwa zapytania równe - pierwsze używa składni ANSI JOIN, drugie to składnia ANSI JOIN. Polecam trzymać się składni ANSI JOIN.

I tak, LEFT OUTER JOINs (które, btw są również składnią ANSI JOIN) są tym, czego chcesz użyć, gdy istnieje możliwość, że tabela, do której dołączasz, może nie zawierać pasujących rekordów.

Reference: Conditional Joins in SQL Server

 3
Author: OMG Ponies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-21 06:51:49

W moim umyśle klauzula FROM to miejsce, w którym decyduję, jakie kolumny potrzebuję w wierszach, aby moja klauzula SELECT działała. Jest to miejsce, w którym wyrażana jest reguła biznesowa, która wprowadzi do tego samego wiersza wartości potrzebne w obliczeniach. Regułą biznesową mogą być klienci, którzy mają faktury, co skutkuje rzędami faktur, w tym odpowiedzialnym klientem. Mogą to być również miejsca o tym samym kodzie pocztowym co klienci, co skutkuje listą miejsc i klientów, które są blisko siebie.

Tu pracuję out centricity rzędów w moim zestawie wyników. W końcu po prostu pokazujemy metaforę listy w RDBMSs, każda lista ma temat (encję), a każdy wiersz jest instancją encji. Jeśli centryczność wiersza jest rozumiana, to jest rozumiana encja zbioru wynikowego.

Klauzula WHERE, która koncepcyjnie wykonuje po wierszach zdefiniowanych w klauzuli from, pobiera wiersze niewymagane (lub zawiera wiersze, które są wymagane) do pracy z klauzulą SELECT.

Ponieważ logika join może być wyrażona zarówno w klauzuli FROM, jak i klauzuli WHERE, a ponieważ klauzule istnieją w celu dzielenia i podbijania skomplikowanej logiki, wybieram umieszczenie logiki join, która obejmuje wartości w kolumnach w klauzuli FROM, ponieważ jest to zasadniczo wyrażenie reguły biznesowej, która jest obsługiwana przez dopasowanie wartości w kolumnach.

Tzn. nie napiszę takiej klauzuli WHERE:

 WHERE Column1 = Column2

Umieszczę to w klauzuli FROM Tak:

 ON Column1 = Column2

Podobnie, jeśli kolumna ma być w porównaniu do wartości zewnętrznych (wartości, które mogą być lub nie mogą być w kolumnie), takich jak porównywanie kodu pocztowego do określonego kodu pocztowego, umieszczę to w klauzuli WHERE, ponieważ zasadniczo mówię, że chcę tylko wierszy takich jak ten.

Tzn. nie napiszę takiej klauzuli:

 ON PostCode = '1234'

Umieszczę to w klauzuli WHERE w następujący sposób:

 WHERE PostCode = '1234'
 1
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-18 21:14:50

Składnia ANSI nie wymusza ani umieszczenia predykatu we właściwej klauzuli (czy to ON czy WHERE), ani powinowactwa klauzuli ON do sąsiedniego odniesienia do tabeli. Programista może napisać taki bałagan

SELECT
   C.FullName,
   C.CustomerCode,
   O.OrderDate,
   O.OrderTotal,
   OD.ExtendedShippingNotes
FROM
   Customer C
   CROSS JOIN Order O
   INNER JOIN OrderDetail OD
      ON C.CustomerID = O.CustomerID
      AND C.CustomerStatus = 'Preferred'
      AND O.OrderTotal > 1000.0
WHERE
   O.OrderID = OD.OrderID;

Mówiąc o narzędziach do zapytań, które "wygenerują ANSI-92", komentuję tutaj, ponieważ wygenerowały

SELECT 1
   FROM DEPARTMENTS C
        JOIN EMPLOYEES A
             JOIN JOBS B
     ON C.DEPARTMENT_ID = A.DEPARTMENT_ID
     ON A.JOB_ID = B.JOB_ID

Jedyną składnią, która wymyka się konwencjonalnemu"ogranicz-projekt-produkt kartezjański" jest zewnętrzne połączenie. Ta operacja jest bardziej skomplikowana, ponieważ jest nie asocjacyjny (zarówno z samym sobą, jak i z normalnym połączeniem). Trzeba rozsądnie parenthesize query z zewnętrznych join, co najmniej. Jest to jednak operacja egzotyczna; jeśli używasz jej zbyt często, sugeruję wzięcie klasy relacyjnej bazy danych.

 0
Author: Tegiri Nenashi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-02 19:38:08