džojnTakéSQL JOIN, join tabulek, databázový joinPokročilý

Definice

JOIN je operace v SQL, která skládá řádky ze dvou nebo více tabulek podle zadané podmínky, typicky podle shody primárního a cizího klíče. Umožňuje číst normalizovaná data jako jeden výsledek, ale může měnit počet řádků i výkon dotazu.

Kategorie: DatabázeAktualizováno

Nezaměňujte: V tomto hesle JOIN znamená spojení tabulek v SQL; v programování vláken může join označovat čekání na dokončení jiného vlákna.

Proč JOIN vzniká v relační databázi

JOIN řeší situaci, kdy jsou související údaje uložené ve více tabulkách. V relačním modelu není obvykle žádoucí kopírovat jméno zákazníka do každé objednávky, protože by se stejná hodnota musela opravovat na mnoha místech. Tabulka objednávek proto drží například customer_id a tabulka zákazníků drží samotné údaje o zákazníkovi.

Dotaz s JOINem říká databázi, podle jaké podmínky má řádky z tabulek spojit do výsledku. Nejčastěji jde o rovnost primárního a cizího klíče. JOIN je tím pádem přirozený doplněk SQL a normalizovaného návrhu dat. Bez něj by normalizace databáze snižovala duplicity, ale ztěžovala čtení dat v podobě použitelné pro aplikaci nebo report.

INNER, LEFT a další druhy JOINu

INNER JOIN vrátí jen dvojice řádků, které splní spojovací podmínku. Pokud objednávka odkazuje na neexistujícího zákazníka, ve výsledku se neobjeví. Tento typ je vhodný, když má být výsledek omezen jen na kompletní shody.

LEFT JOIN zachová všechny řádky z levé tabulky a doplní hodnoty z pravé tabulky tam, kde existuje shoda. Pokud shoda chybí, sloupce z pravé tabulky dostanou hodnotu NULL. LEFT JOIN se často používá při hledání chybějících vazeb, volitelných údajů nebo nevyplněných stavů.

RIGHT JOIN je zrcadlová varianta LEFT JOINu a FULL OUTER JOIN zachová nespárované řádky z obou stran. CROSS JOIN vytvoří kartézský součin, tedy každou kombinaci řádku z první a druhé tabulky. CROSS JOIN bývá užitečný při generování kombinací, ale omylem může rychle vytvořit obrovský výsledek.

Podmínka spojení rozhoduje o významu výsledku

Nejdůležitější část JOINu není samotné slovo JOIN, ale klauzule ON. Podmínka určuje, které řádky spolu souvisejí. Špatně zvolený sloupec může vrátit výsledek, který technicky projde, ale obchodně nedává smysl. Například spojení zákazníků s objednávkami podle jména místo identifikátoru selže u duplicitních jmen.

JOIN může také násobit řádky. Jeden zákazník s pěti objednávkami se ve výsledku objeví pětkrát. Tento efekt je správný, pokud dotaz vypisuje objednávky, ale překvapí při počítání zákazníků. Agregace pak často potřebuje COUNT(DISTINCT ...) nebo jiné upřesnění záměru.

Cena JOINu v dotazovacím plánu

Databázový optimalizátor vybírá konkrétní algoritmus spojení podle statistik, indexů, odhadované velikosti tabulek a podmínek dotazu. JOIN nad malými tabulkami může být levný, zatímco spojení velkých tabulek bez vhodného indexu může znamenat mnoho čtení a třídění.

Index na sloupci použitém ve spojovací podmínce často pomůže, ale není automatickou zárukou rychlosti. Výkon ovlivňuje selektivita, typ JOINu, filtry v WHERE, aktuálnost statistik i to, zda dotaz vrací detailní řádky nebo agregovaný přehled.

Příklady z praxe

  1. Objednávky s e-mailem zákazníka

    E-shop potřebuje vypsat objednávky společně s e-mailem zákazníka. INNER JOIN vrátí jen objednávky, které mají odpovídající záznam v tabulce customers. Objednávka s poškozeným customer_id se do výsledku nedostane, což může být žádoucí pro čistý export, ale nevhodné pro audit chyb.

    SELECT o.id, o.created_at, c.email
    FROM orders AS o
    INNER JOIN customers AS c
      ON c.id = o.customer_id;
  2. Produkty bez kategorie

    Správce katalogu hledá produkty, kterým chybí platná kategorie. LEFT JOIN zachová všechny produkty a u produktů bez shody v categories doplní NULL. Podmínka ve WHERE pak vybere právě problematické položky, které by INNER JOIN úplně skryl.

    SELECT p.id, p.name, c.name AS category_name
    FROM products AS p
    LEFT JOIN categories AS c
      ON c.id = p.category_id
    WHERE c.id IS NULL;

Časté omyly

MýtusJOIN jen přidá sloupce z druhé tabulky.
Ve skutečnostiJOIN může přidat sloupce, ale současně může filtrovat nebo násobit řádky podle počtu shod. Výsledek závisí na typu JOINu a podmínce v ON.
MýtusLEFT JOIN je vždy bezpečnější než INNER JOIN.
Ve skutečnostiLEFT JOIN zachová nespárované řádky z levé tabulky, ale tím může do výsledku dostat NULL hodnoty a změnit význam filtrů. INNER JOIN je správnější, pokud dotaz vyžaduje existující shodu.
MýtusIndex na cizím klíči vždy vyřeší pomalý JOIN.
Ve skutečnostiIndex často pomůže, ale výkon JOINu závisí také na velikosti tabulek, selektivitě, filtrech, statistikách a tvaru dotazu. Plán dotazu je spolehlivější vodítko než samotná existence indexu.

Časté dotazy

Kdy má JOIN zůstat v databázi místo ve zdrojovém kódu aplikace?
JOIN obvykle patří do databázového dotazu, když aplikace potřebuje konzistentní data z více tabulek a spojení lze vyjádřit jasnou relační podmínkou. Spojování v aplikaci může dávat smysl u malých doplňkových seznamů, cache nebo dat z různých systémů. Databáze však často zvládne filtrování, spojení a agregaci efektivněji, protože má statistiky, indexy a optimalizátor dotazů.
Proč je některý JOIN v SQL pomalý?
JOIN sám o sobě nemusí být pomalý. Pomalost obvykle vzniká z velkého objemu dat, chybějících nebo nevhodných indexů, nepřesných statistik, špatné spojovací podmínky nebo z dotazu, který vrací víc řádků, než aplikace potřebuje. Pro posouzení výkonu je důležitý plán dotazu, protože databáze může použít různé strategie spojení podle konkrétních tabulek a filtrů.
Kdy použít LEFT JOIN místo INNER JOINu?
LEFT JOIN je vhodný, když výsledek musí obsahovat všechny řádky z první tabulky bez ohledu na to, zda existuje odpovídající řádek ve druhé tabulce. Typický případ je seznam produktů včetně volitelné kategorie nebo kontrola objednávek bez platného zákazníka. INNER JOIN by nespárované řádky odstranil, takže by mohl skrýt právě ta data, která chce dotaz odhalit.
Proč JOIN vrací více řádků než původní tabulka?
JOIN může změnit počet řádků, protože jedna shoda na levé straně může odpovídat více řádkům na pravé straně. Zákazník se třemi objednávkami se po spojení se seznamem objednávek objeví třikrát. Výsledek není chyba, pokud dotaz pracuje s objednávkami, ale při počítání zákazníků je potřeba agregovat opatrně a často použít DISTINCT nebo seskupení.

Zdroje

  1. 7.2. Table Expressions(otevře se v novém okně)PostgreSQL Global Development Group
  2. SELECT(otevře se v novém okně)SQLite
  3. Joins(otevře se v novém okně)Microsoft

Související pojmy

Potřebujete to vyřešit v praxi?

Poradíme, jak na to ve vašem projektu

Vysvětlit pojem je jedna věc, navrhnout kolem něj funkční řešení druhá. Ozvěte se a probereme, co dává smysl u vás.