2010-01-21 11 views
5

I często znajduję się chce napisać zapytanie SQL tak:SQL: Czy takie zapytanie jest prawidłowe, czy jest bardziej efektywny sposób na to, np. Przy użyciu sprzężenia?

SELECT body 
    FROM node_revisions 
where vid = (SELECT vid 
       FROM node 
       WHERE nid = 4); 

Wiem, że istnieją przyłącza i rzeczy można zrobić, ale wydaje się, aby rzeczy bardziej skomplikowane. Czy łączenia są lepszym sposobem na zrobienie tego? Czy jest bardziej wydajny? Łatwiej zrozumieć?

+1

Byłbym skłonny założyć się, że na serwerze SQL to zapytanie i logicznie równoważne połączenie będą miały identyczne plany wykonywania zapytań. – Dana

Odpowiedz

7

Łączy wydają się być bardziej wydajny od baz danych są zapisywane z zestawu operacji na uwadze (i przyłącza są operacje).

Wydajność będzie jednak różnić się w zależności od bazy danych, sposobu, w jaki są uporządkowane tabele, ilości danych w nich i ilości zwracanych przez zapytanie.

Jeśli ilość danych jest niewielka, użyłbym podkwerendy takiej jak twoja zamiast dołączania.

Oto co przyłączyć wyglądałby następująco:

SELECT body 
FROM node_revisions nr 
INNER JOIN node n 
    ON nr.vid = n.vid 
WHERE n.nid = 4 

Nie chciałbym użyć zapytania pan pisał, ponieważ nie ma szans na więcej niż jeden rekord węzła z nid = 4, co mogłoby spowodować jego uszkodzenie.

użyłbym:

SELECT body 
FROM node_revisions 
WHERE vid IN (SELECT vid 
      FROM node 
      WHERE nid = 4); 

jest to bardziej czytelne i zrozumiałe? W tym przypadku jest to kwestia osobistych preferencji.

+0

To więcej niż osobiste preferencje. Chciałbym zobaczyć sprzężenie na dwóch kolumnach przy użyciu IN, które porównuje czytelność. Szczerze mówiąc, nadużywanie IN, dla mnie, może być symptomem zasadniczego problemu konceptualnego w SQL. – ErikE

1
select 
    body 
from node_revisions A 
where exists (select 'x' 
       from Node B 
       Where A.Vid = B.Vid and B.NID=4) 
+2

Dlaczego jest lepiej? Wydaje się to bardziej skomplikowane. –

+0

Jest to bardziej skomplikowane, ale nie robi tego samego. Jest to połączenie typu semi-join, które w niektórych przypadkach pozwala serwerowi bazy danych na przeprowadzenie optymalizacji. Zawsze też zwróci tylko jeden wiersz z głównej tabeli, niezależnie od tego, ile pasujących wierszy znajduje się w tabeli podzapytania. Zauważ, że nie możesz odwołać się w głównej kwerendzie do kolumn w podzapytaniu, ale to jest sedno: sprawdzasz * istnienie *, nie wyciągasz danych.Ponadto, jeśli tabela podzapytania ma WIELE wierszy na wiersz w tabeli zewnętrznej, istniejąca składnia może być znacznie bardziej wydajna, ponieważ może zatrzymać się po znalezieniu tylko jednego. – ErikE

+0

To nie jest logiczne odpowiednik pierwotnego zapytania. W przypadku podkwerendy zwracającej wiele wierszy, to zadziała, a pierwotne zapytanie zakończy się niepowodzeniem. Byłby to odpowiednik zapytania z 'IN' zamiast' = '. Jednak wszystkie nowoczesne silniki mogą zoptymalizować zarówno "EXISTS" i "IN" do semi-join. – Quassnoi

3

Odpowiedź na wszelkie pytania związane z wydajnością w bazach danych jest zależy i jesteśmy mało szczegółów w PO. Znając żadnych szczegółów na temat swojej sytuacji ... (a więc są to ogólne zasady kciuka)

przyłącza są lepsze i łatwiejsze do zrozumienia

  • Jeśli z jakiegoś powodu trzeba wiele kluczy kolumn (podejrzany) , możesz nadal używać sprzężenia i po prostu dostosowywać inne wyrażenie do warunku łączenia.
  • Jeśli w przyszłości naprawdę konieczne będzie dołączenie danych pomocniczych, struktura łączenia już istnieje.
  • Uściśla dokładniej, do czego przyłącza się i gdzie należy zaimplementować indeksy.
  • Użycie łączeń pozwala lepiej połączyć i lepiej myśleć o złączeniach.
  • przyłącza są jasne, o co tabele są w grze

pisemne pytania nie mają nic wspólnego z effiency *

zapytań pisać i co faktycznie pobiera uruchamiane mają niewiele wspólnego ze sobą. Istnieje wiele sposobów pisania zapytań, ale tylko nieliczne sposoby pobierania danych i decyzja o tym decyduje mechanizm zapytań. Dotyczy to głównie indeksów. Bardzo możliwe jest napisanie czterech zapytań, które wyglądają zupełnie inaczej, ale wewnętrznie robią to samo.

(* Jest to możliwe, aby napisać kwerendę, która jest straszną nieefektywne ale ma specjalny rodzaj szalony, aby to zrobić.)

select 
    body 

from node_revisions nr 

join node n 
on n.vid = nr.vid 

where n.nid = 4 
1

Najnowszy kod MySQL 6.x automatycznie przekonwertować do ekspresji INNER JOIN używając naczepa dołączyć optymalizacji podzapytania, dokonywania sprawozdań 2 w dużej mierze równoważne:

http://forge.mysql.com/worklog/task.php?id=3740

ale faktycznie pisanie go jest bardzo proste do zrobienia, ponieważ INNER JOIN jest domyślnym typem sprzężenia, a wykonanie tego nie będzie zależało od serwera optymalizującego go (z którego może zrezygnować z jakiegoś powodu i który nie będzie przenośny). Wszystkie rzeczy są równe, to dlaczego nie iść z:

select body from node_revisions r, node n where r.vid = n.vid and n.node = 4 
3

Myślę, że łączenie jest łatwiejsze do zrozumienia i może być bardziej wydajne. Twoja sprawa jest dość prosta, więc prawdopodobnie jest to toss-up. Oto jak bym ją napisać:

SELECT body 
    FROM node_revisions 
    inner join node 
     on (node_revisions.vid = node.vid) 
    WHERE node.nid = 4 
1

nie widzę nic złego z tym, co napisałeś, a dobry optymalizator może nawet zmienić go do przyłączenia się, jeśli uzna to za stosowne.

1
SELECT body 
FROM node_revisions 
WHERE vid = 
     (
     SELECT vid 
     FROM node 
     WHERE nid = 4 
     ) 

To zapytanie jest logicznie równoważne do sprzężenia wtedy i tylko wtedy nid jest PRIMARY KEY lub jest objęty UNIQUE ograniczeń.

przeciwnym razie zapytań nie są równoważne: złączenia zawsze uda, podczas gdy podzapytanie nie powiedzie się, jeśli istnieje więcej niż 1 wiersz node z nid = 4.

Jeśli nid jest PRIMARY KEY, wówczas JOIN i podzapytanie będą miały taką samą wydajność.

w przypadku przyłączenia, node będzie wiodącym

W przypadku podzapytania, podzapytanie będzie wykonywana raz i przekształcony w const na etapie analizowania.

+0

Yup, nid i vid są unikalnymi kluczami podstawowymi. –

+0

'@Brian T. Hannan': wtedy zapytania są identyczne. 'JOIN' i podzapytanie wykonają to samo. – Quassnoi

2

JOIN jest ciekawe:

select body 
from node_revisions nr 
join node n on nr.vid = n.vid 
where n.vid = 4 

Ale można też wyrazić sprzężenia bez kwadratu [!]:

select body 
from node_revisions nr, node n 
where n.nid = 4 and nr.vid = n.vid 

Co ciekawe, SQL Server daje niewielkie inny plan kwerend na obu kwerendy, podczas gdy join ma sklasyfikowany indeks, "join without a join" ma indeks klastrowany w jego miejsce, co oznacza, że ​​jest to better, przynajmniej w tym przypadku!

Powiązane problemy