Netradiční zápisy spojení a úvaha nad rychlostí spojování tabulek - to je téma dnešního dílu seriálu o MySQL.
27.5.2005 09:00 | Petr Zajíc | přečteno 65967×
Dnes si rozebereme některé věci, které se týkají spojování tabulek a
které byste měli znát. Nebo takové, o nichž byste měli alespoň tušit,
že existují. Spojování tabulek je totiž tak v databázovém světě tak
důležité, že se bez něj v naprosté většině aplikací zkrátka neobejdete.
Na těchto typech spojení je exotické to, že je většina vývojářů nebo
projektů téměř nepoužívají. Na jednu stranu se nepoužívají proto, že k
tomu není důvod, na druhou stranu je dobré o nich vědět. Takže, která
spojení to jsou?
CROSS JOIN spojí tabulky tak, že výsledkem je jejich kartézský součin. To znamená, že pro každý řádek z jedné tabulky je ve výsledné sadě záznamů vytvořena kombinace se všemi řádky z tabulky druhé. Má-li tedy první tabulka 5 řádků a druhá 2 řadky, bude ve výsledné množině řádků deset. CROSS JOIN tabulky knih a druhů bychom mohli zapsat takto:
select * from knihy
cross join druhy;
Třebaže se to nezdá, s tímto příkazem jsme se již v seriálu setkali, a to v jiné formě v díle o základech spojování. On je totiž předchozí příklad ekvivalentní zápisu
select * from knihy,
druhy;
a abychom byli politicky korektní, je rovněž významem roven zápisu
select * from knihy join
druhy;
Sady vrácené pomocí CROSS JOIN bývají málokdy tak smysluplné, aby je
šlo v reálných aplikacích nějak použít. Typickou chybou pro začátečníky
v oblasti spojování tabulek je vytvoření příkazu CROSS JOIN a následné
"vyzobávání" potřebných záznamů pomocí klauzule WHERE nebo pomocí
procházení výsledné sady záznamů. V praxi bývá většinou na místě
použití INNER JOIN nebo LEFT JOIN.
Jako obecná zásada tedy může sloužit tvrzení, že používáte-li CROSS JOIN, pak nejspíš máte pomalé databázové aplikace, špatný návrh struktury databáze nebo obojí.
Takže, nejprve definice: NATURAL JOIN (a NATURAL LEFT JOIN) je roven takovému příkazu JOIN (a LEFT JOIN), kde jsou použity všechny sloupce z obou tabulek, které se stejně jmenují. Tahle věcička patří k těm, které se rozhodnete milovat nebo nenávidě, ale nic mezi tím. NATURAL JOIN se pochopitelně dá vždy přepsat jako odpovídající JOIN. Uveďme ale příklad, jak by takové spojení mohlo vypadat:
select * from knihy
natural join druhy;
Pokud si to zkoušíte, zjistíte, že tento dotaz nevrátí pro naše
tabulky žádná data. Proč? Podívejte se na strukturu tabulek! Která pole
se jmenují stejně? ID a název - a neexistuje záznam, v němž by byly v
našem příkladu shodné. Přiznám se, že patřím k těm, kdo NATURAL JOIN
moc v
lásce nemají. Pokud byste chtěli vědět proč, tady jsou moje důvody:
Pozn.: Ten poslední bod je samozřejmě
vyvratitelný. Nic by mi nebránilo nazvat si v tabulce druhů sloupec s
primárním klíčem třebas druh_id. Kdybych pak v tabulce knih rovněž
odkazující sloupec nazval druh_id, NATURAL JOIN by se dal použít a
určitá koncepce pojmenování tabulek by taky zůstala. Nicméně, zvyk je
železná košile.
Uvědomme si, že NATURAL JOIN použije pro spojení všechna shodná
pole. O něco elegantnější je následující konstrukce.
Toto rozšíření funguje tak, že sice rovněž spojuje pomocí shodně nazvaných polí v obou tabulkách, ale umožňuje nám tato pole vyjmenovat. Kdybychom v našem příkladu měli skutečně pole zastupující žánr knihy nazváno druh_id, mohli bychom příkaz
select * from knihy join
druhy on knihy.druh_id = druhy.druh_id;
přepsat použitím JOIN ... USING na
select * from knihy join
druhy using (druh_id);
Jak vidíte, tím padají všechny moje argumenty ohledně
nepoužitelnosti NATURAL JOIN, protože tento zápis spojení je celkem
přehledný a dá se použít. Nicméně, stále to vyžaduje mít odpovídající
pole ve spojovaných tabulkách nazvána stejně. Pochopitelně, že lze
rovněž použít zápis LEFT JOIN ... USING a RIGHT JOIN ... USING.
Zaznamenal jsem některé dotazy v diskusi nebo e-mailech, které
souvisely s výkonem spojení. Pokusím se teď na ně odpovědět.
Ne, manuál
k mysql na stránce o optimalizaci spojení tvrdí, že "RIGHT JOIN je
imlementováno analogicky k LEFT JOIN s tím, že role obou tabulek jsou
prohozeny". Nemusíte se tedy bát. Skutečně není nutné vyměňovat v
zápisu spojení tabulky jen proto, abychom dosáhli zvýšení rychlosti.
V naprosté většině případů bude spojení
více tabulek stejně to nejrychlejší možné řešení. Ostatní možnosti
(například, uložení jednoho spojení do dočasné tabulky a její použití
při dalším spojení) budou až řádově pomalejší.
První věcí, kterou je třeba zmínit jsou indexy. V seriálu o nich bude teprve řeč, takže vydržte. Měli byste zvážit použití indexu pro spojení, protože toto spojení pak může být mnohem rychlejší. Druhá věc - a tu můžeme uvést hned - měli byste se pokud možno vyhýbat použití čehokoli jiného kromě názvu sloupců v definici spojení. Například následující spojení je sice syntakticky správné a MySQL jej provede.
select * from
zamestnanec join pozice on zamestnanec.pozice = pozice.id+3;
Protože však je součástí spojovací podmínky výraz (pozice.id+3), nemůže nebohá databáze provést žádnou optimalizaci a bude zřejmě při sestavování spojení muset procházet tabulkou "pozice".