Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Matúš Petrofčík:

Mam tabulku s inzeratmi, a tie maju atributy ako id, nazov, popis... id mesta, id regionu...
Dalsimi tabulkami je tabulka miest a tabulka regionov ktore obsahuju id a nazov mesta/regionu. Prosim poradte mi ako spravit takyto join viacerych tabuliek do jednoho query, aby mi vyplulo zoznam inzeratov, a kazdy inzerat bude mat id, nazov, popis, meno mesta, meno regionu...

Dakujem za pomoc s vysvetlenim a vyskladanim viacnasobneho joinu. :) MP

Editováno 18.10.2014 16:19
Odpovědět 18.10.2014 16:18
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Pavel Mareš
Redaktor
Avatar
Odpovídá na Matúš Petrofčík
Pavel Mareš:

Toto jsem dělal v prváku (2 roky zpět) při programování něčeho podobného. Ale tento postup je špatně. Ano jde to, ale tento postup se používá jednou za delší čas, jelikož je nároční na výpočet a bla bla bla. Já ti doporučuji si vytvořit vždy napojení na jednu tabulku v cyklu a tom bude další cyklus na napojení k další tabulce. Je to standardní postup.

Nahoru Odpovědět 18.10.2014 16:41
Nechci být workoholik. Bohužel někdy musíme být tím, čím nechceme.
Avatar
Richard
Člen
Avatar
Odpovídá na Pavel Mareš
Richard:

S tím že to není ideální řešení souhlasím. Ale query v cyklu taky není úplně OK.. Nacpal bych id a názvy do array a pak přiřazoval.

Nahoru Odpovědět 18.10.2014 16:52
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
Tukmak
Člen
Avatar
Odpovídá na Matúš Petrofčík
Tukmak:

Ahoj, join má základní syntaxi:

JOIN nazev_tabulky USING (pk_pro_spojeni)

Slovy řečeno připojuješ tabulku pomocí primárního klíče. V tvém případě by to mohlo vypadat takto:

SELECT nazev, popis, inzeraty.id_mesta, inzeraty.id_regionu, nazev_mesta, nazev_regionu FROM inzeraty
JOIN regiony USING(inzeraty.id_regionu)
JOIN mesta USING(inzeraty.id_mesta)
WHERE nejaka_podminka
 
Nahoru Odpovědět  +1 18.10.2014 16:53
Avatar
Odpovídá na Matúš Petrofčík
Martin Konečný (pavelco1998):

Zkus něco takovýho

<?php

$inzeraty = $db->fetchAll("
  SELECT `inzerat`.`id`, `inzerat`.`nazev` AS nazevInzeratu, `inzerat`.`popis`,
    `mesto`.`nazev` AS nazevMesta,
    `region`.`nazev` AS nazevRegionu
  FROM `inzerat`
  INNER JOIN `mesto` ON `inzerat`.`mestoId` = `mesto`.`id`
  INNER JOIN `region` ON `inzerat`.`regionId` = `region`.`id`
");

foreach ($inzeraty as $inzerat) {
  echo "Inzerát: {$inzerat->nazevInzeratu}, Město: {$inzerat->nazevMesta}, Region: {$inzerat->nazevRegionu}<br />";
}

Dávat jeden query na inzeráty a pak v cyklu další dva dotazy pro město a region není dobrej nápad, protože tím pak posíláš velké množství dotazů do DB.

Editováno 18.10.2014 17:12
Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
 
Nahoru Odpovědět  +2 18.10.2014 17:09
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Matúš Petrofčík:

pavelco, práve to je ten problém, že teraz to mám riešené cez 1 query na vytiahnutie poľa inzerátov, a potom mám foreach na všetky tieto inzeráty a pri každom cykle sa mi vykoná 5 query do databázy, a došli mi že to nie je správna cesta :D vypísanie 3 skúšobných inzerátov síce funguje super, vygenerovanie stránky ma stojí 650ms, čo nie je pri 3 inzerátoch ani trošičku v poriadku :/

Všetkým moc ďakujem za pomoc, ale pre úplnosť doplním: každý inzerát má id mesta, regionu, kategorie, podkategorie, inzerenta. Tieto 5 id sa musia nahradiť názvami. Je v poriadku pre databázu mať taký 5+ násobný join? jedná sa o postgres db. Ak to nie je v pohode, asi to spravím ako radil Richard (Nacpal bych id a názvy do array a pak přiřazoval.)

Nahoru Odpovědět 18.10.2014 18:49
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Tukmak
Člen
Avatar
Odpovídá na Matúš Petrofčík
Tukmak:

Pokud máš velkou databázi, tak proč by to nemělo být v pořádku? Select, kde je 5× join je mnohem efektivnější než 5× samotný select.

Pokud si o tom chceš přečíst něco víc, stačí googlit (https://www.google.cz/search?…)

 
Nahoru Odpovědět  +2 18.10.2014 19:07
Avatar
Odpovídá na Matúš Petrofčík
Martin Konečný (pavelco1998):

Nevím, jaké přesně JOINy mají nevýhody, ale mám pocit, že přesně kvůli takovýmto případům se vytvářely. Koukal jsem na pár článků a diskusí a prakticky všude se psalo, že použití JOINů je lepší, než posílat několikanásobně víc dotazů (byť jednoduchých).

 
Nahoru Odpovědět  +3 18.10.2014 19:14
Avatar
Richard
Člen
Avatar
Richard:

Když ony ty joiny sou takový zvěrstvo.. Pokud se využijí pole, ta data se budou moci dále použít, asi je to jen moje antipatie k joinům.

Postup bych si představoval asi takto: cyklem najít inzeráty, v každém cyklu zapsat do proměnné další where klauzoli, která se pak použije v sql dotazu (vím, blbej způsob, ale pro tu myšlenku to stačí a ušetří to spoustu dat) a samotná data z tabulky zapsat do pole. Po projetí vybrat data z ostatních tabulek, nacpat do pole k původním datům ta další a pak jen vypsat.

V některých případech bude i tento způsob o něco rychlejší, ikdyž uznávám že zápis je delší. Víc výhod má zřejmě join, pokud s nimi nemáš problém, použij join.

Nahoru Odpovědět 18.10.2014 19:36
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Richard
Matúš Petrofčík:

to asi ne, pretože by to chcelo 6 selectov za sebou

  1. zoznam inzerátov
  2. zoznam miest
  3. zoznam regionov
  4. zoznam kategorii
  5. zoznam podkategorii
  6. zoznam mien ľudí

a potom prehnať 1. zoznam foreachom a nahradiť idčka podľa 2. až 6. zoznamu

kde to join spraví všetko za mňa a rovno vypľuje to čo chcem (teda aspoň tak si to predstavujem :D ). ten join bude asi najrozumnejší, tak ho skusím, a ak bude trvať kratšie než to trvá teraz, tak už toto bude podľa mňa výhra :D

Editováno 18.10.2014 19:51
Nahoru Odpovědět 18.10.2014 19:50
obsah kocky = r^2 ... a preto vlak drnká
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Matúš Petrofčík
David Čápka:

To máš někde chybu, pár joinů v selectu je naprosto v pořádku a uvědom si, že joinuješ podle primárního klíče, tohle je dost rychlé a používá se to běžně. Hlavně tam nevymýšlej žádné cykly.

Nahoru Odpovědět  +1 18.10.2014 19:53
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Richard
Člen
Avatar
Odpovídá na Matúš Petrofčík
Richard:

Však píšu ať použiješ join, pro tenhle případ lepší volba.

Nahoru Odpovědět 18.10.2014 19:54
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
Odpovídá na Richard
Michal Štěpánek:

Zcela jistě ti můžu říct, že použití JOINu bude vždycky rychlejší, než použití cyklů a několika SELECTů. Ale je otázka, k čemu se ty konkrétní způsoby použijí. Když budu potřebovat v jednom řádku výpisu mít více hodnot z jiné tabulky, tak to JOINem nepůjde a musí se použít cykly. Pokud však jde o pouhé nahrazení identifikátorů jménem (z číselníku), pak je JOIN naprosto nejlepší volbou.

Nahoru Odpovědět 18.10.2014 19:55
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Richard
Člen
Avatar
Odpovídá na Michal Štěpánek
Richard:

Pokud jde o jednoduché zadání jako zde tak ano, protože těch dat bude pár a na jednom místě, budou se jednorázově používat, nic dalšího ani složitějšího se s tim dělat nebude. Jsem asi už deformovanej, u nás joiny prostě použít nemůžeme, proto je podvědomě odkládám na druhou kolej.

Chci tím říct, že ikdyž je join mnohdy rychlejší, ne vždy je to spása.

Editováno 18.10.2014 20:02
Nahoru Odpovědět 18.10.2014 20:01
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Richard
David Čápka:

A kde pracuješ? To mi přijde jako nesmysl, JOINY potřebuješ ať chceš nebo ne a zanášet výběr dat do logické vrstvy je hodně špatný nápad, k tomu ta databáze je.

Nahoru Odpovědět 18.10.2014 20:21
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Richard
Člen
Avatar
Odpovídá na David Čápka
Richard:

Analýza statistických dat + big data.
Pokud vypisuješ pár dat z databáze, tak ti to stačí, ale pokud s těmi daty potřebuješ pracovat, tisíckrát třídit, porovnávat, pokud potřebuješ z jedný tabulky mnoho sad dat podle určitých parametrů, budeš mít buďto 10000 query s joinama, a stejně to budeš zpracovávat, akorát blbějc, nebo několik jednotek jendoduchých query a budeš mít k dispozici kompletní sady dat.

Uznávám že doporučovat tady něco jinýho než join byl fail, ale mnohem větší fail je tvrdit že bez joinu se člověk nikdy neobejde, nehledě na druhou část tý věty.

Neber to jako útok, naopak tě opravdu uznávám, ale pokud s něčím nemáš zkušenosti, nemůžeš tvrdit že to funguje jednotně všude a že všude je ten nebo onen způsob správný.

Nahoru Odpovědět 18.10.2014 20:41
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Richard
David Čápka:

Jestli s těmi daty děláš další složité výpočty, tak na to databáze moc není, tomu bych věřil. Nějak se mi ale nechce věřit tomu, že bys takhle jednoduchý problém jako řeší autor dotazu urychlil v aplikaci a i kdyby ano, tak on nikdy nedosáhne takového počtu dat, aby se tím vůbec vyplatilo zabývat. S tímhle mám zas zkušenosti já, máme očividně odlišné světy a zde řešený problém přijde blíže tomu mému, protože těch inzerátů asi nemá miliony.

Nahoru Odpovědět 18.10.2014 21:11
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Richard
Člen
Avatar
Odpovídá na David Čápka
Richard:

Tak ani jeden netušíme kolik dat bude nebo co s tím dál bude dělat (jo, nejspíš pár a vypíše to, ale co kdyby :D), ale uznal jsem že join je určitě lepší volba a že doporučovat něco jiného byl fail.

Nahoru Odpovědět 18.10.2014 21:23
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Matúš Petrofčík:

len tak pre zaujímavosť:
pomocou obyčajného selectu bez joinov získať zoznam 3 vyhovujúcich inzerátov, a následne foreach cez tieto inzeráty kde sa pri každom volali ďalšie 2 selecty aby sa namiesto id mesta a id regionu nahradili názvy miest a názvy regionov... 320-350ms

pomocou selectu s dvoma jednoduchými joinami kde mi namiesto id mesta a id regionu doplnila názvy miest a názvy regionov databáza... 180-220ms

a to ide len o 3 inzeráty :) čo by to s tým foreachom a ďaľšími selectami bolo, keby ich tam bolo 100 :D možno to neskôr vyskúšam

pomohol som si s riešením ktoré tu dal Martin Konečný (pavelco1998), to od Tukmaka mi na Postgrese 9.0 nefunguje :)

Nahoru Odpovědět 19.10.2014 22:26
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Odpovídá na Matúš Petrofčík
Martin Konečný (pavelco1998):

Heh děkuji za označení.

Btw, jedno příliš nepobírám - jak může tak jednoduchý SQL dotaz zabít tolik času?
Že se mi aplikace v Nette na localhostu načítá asi 1000ms, to je ještě v poho (EXPLAIN SQL dotazu je většinou kolem 0.0003s), ale jeden query 200ms?

 
Nahoru Odpovědět 19.10.2014 23:23
Avatar
Tukmak
Člen
Avatar
Odpovídá na Matúš Petrofčík
Tukmak:

Jasně, asi jsem se zapomněl zmínit... USING je zkratka pro JOIN ON, ale dá se použít jen za předpokladu, že sloupce v obou tabulkách, přes které tabulky spojuješ, mají stejné jméno.

 
Nahoru Odpovědět  +1 19.10.2014 23:26
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Tukmak
Matúš Petrofčík:

ja si schválne dávam názvy v tabuľkách takto: inzety - inzerat_id, inzerat_nazov... a to z toho dôvodu, že raz budem používať joiny, tak aby som sa na 1000% niekde nepomýlil, a ak potrebujem tak si ich cez inzerat_id AS id premenujem :) nikdy som však joiny nepotreboval, tak som úplne zabudol ako ich používať :D zatiaľ mi takéto pomenovanie tabuliek a atributov vyhovuje, no možno to zmením ak na to bude dobrý dôvod

Nahoru Odpovědět 19.10.2014 23:37
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Matúš Petrofčík:

No pôvodne som to robil takto:

  1. query do db - vybrať zoznam inzerátov vyhovujúcich podmienke
  2. prehnať zoznam inzerátov cez foreach a pozmeniť/doplniť ich údaje pre výpis podľa potreby

ten 2. krok pozostával z opakovania týchto krokov:

  1. query do db - získať názov mesta podľa id
  2. query do db - získať názov regionu podľa id
  3. query do db - získať názov kategorie podľa id
  4. query do db - získať názov podkategorie podľa id
  5. query do db - získať názov stavu produktu podľa id
  6. query do db - získať názov ceny produktu podla id pokial nie je zadaná hodnota v cene
  • ešte 3 query :D

pri 3 inzerátoch to máme 1 + 3*9 selectov :) a to bol problém, pre ktorý som toto vlákno zakladal :D

teraz mám všetko v jednom selecte :3

ešte jeden postreh: predtým mi výpis nednoho inzerátu trval 550-600ms, teraz 80-100ms :D takže joiny vedieť je veľmi výhodné, aj napriek tomu že mám v jednom selecte 8 joinov ;)

Editováno 19.10.2014 23:44
Nahoru Odpovědět 19.10.2014 23:43
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Odpovídá na Matúš Petrofčík
Martin Konečný (pavelco1998):

Obvykle i ty SELECTy by měly být rychlé, když jsou jednoduché a hledáš podle primárního klíče. Nicméně ty JOINy se mi zdají pro tento účel lepší a zároveň snazší na použití (prostě máš všechna data ihned pohromadě).

Já mám v jednom query dotazu 11 joinů (9x LEFT, 2x INNER) a dle EXPLAIN v tom není žádný problém.

Editováno 19.10.2014 23:53
 
Nahoru Odpovědět 19.10.2014 23:53
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Matúš Petrofčík:

Mohol by si mi prosím ešte v rýchlosti vysvetliť rozdiely a použitie INNER a OUTER, LEFT a RIGHT joinov prosím? ja už musím ísť spať tak si to zajtra pozriem, ak teda máš na to času :)

Nahoru Odpovědět 19.10.2014 23:58
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Odpovídá na Matúš Petrofčík
Martin Konečný (pavelco1998):

http://stackoverflow.com/…nd-full-join :)

Nechce se mi to moc slovně popisovat, protože bych ti určitě napsal něco špatně.
Jakože vím, v jakém případě jaký použít, ale kdybych ti to měl napsat, tak bych se v tom možná trochu zamotal.

Editováno 20.10.2014 0:04
 
Nahoru Odpovědět  +2 20.10.2014 0:02
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Matúš Petrofčík:

To je pravda :) sú tam pekné grafy, ďakujem

Nahoru Odpovědět 20.10.2014 8:34
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Odpovídá na Matúš Petrofčík
Martin Konečný (pavelco1998):

Jojo v poho. Osobně jsem třeba RIGHT JOIN použil snad jen jednou za život, OUTER nebo CROSS nikdy. Nejvíc se využije INNER a LEFT.

 
Nahoru Odpovědět 20.10.2014 8:36
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Michal Štěpánek:

Já OUTER používám poměrně často. Když zobrazuju ve své aplikaci detail požadavku, tak ve stavu NOVÝ ještě není v DB vyplněn "řešitel", "datum řešení" apod. Abych nemusel pro každý stav požadavku dělat extra zobrazení, udělám jen jedno a při použití OUTER se mi prostě jen ty prázdné údaje nezobrazí. Kdybych použil INNER nezobrazí se vůbec nic, protože INNER vyžaduje vyplněné všechny vybírané položky...

Nahoru Odpovědět 20.10.2014 10:29
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Odpovídá na Michal Štěpánek
Martin Konečný (pavelco1998):

Pokud jsem tvůj případ pochopil dobře, pak to obvykle řeším LEFT JOINem, kdy z druhé tabulky dostanu NULL.
Je ale pravda, že OUTER moc neznám a je možné, že by se mi v některých případech hodil líp.
Díky :)

 
Nahoru Odpovědět 20.10.2014 12:11
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Martin Konečný (pavelco1998)
David Čápka:

Levý a pravý JOIN je vždy OUTER :) INNER je ten výchozí.

Nahoru Odpovědět  +2 20.10.2014 12:29
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Michal Štěpánek:

Jak píše David Čápka , když napíšeš LEFT JOIN, tak jsi použil LEFT OUTER JOIN. LEFT nebo RIGHT určuje pouze stranu dotazu, na které se mohou vyskytovat prázdné položky...

Editováno 20.10.2014 12:47
Nahoru Odpovědět 20.10.2014 12:46
Nikdy neříkej nahlas, že to nejde. Vždycky se totiž najde blbec, který to neví a udělá to...
Avatar
Richard
Člen
Avatar
Odpovídá na Matúš Petrofčík
Richard:

Zajímavá čísla, ještě jsem to rozšířil (měřeno na desktopu, takže nic přesného, průměr z 5 opakování):

Query s joinem: 0.0018 s
Query a v cyklu query na zjištění názvů měst a regionů: 0.0041 s
Query na inzeráty, data o městech a regionech (3x query), všechno nacpáno do polí a následně přiřazeno: 0.0023 s

To všechno s téměř s prázdnou tabulkou (3 inzeráty, 3 regiony, 3 města).
Pokud záznamy začnou přibývat, query s joinem nemá problém, druhá možnost se extrémně zpomaluje, a třetí možnost jen mírně (kvůli procházení větším polem).

PS. Na čem si to měřil, že to tomu hw trvalo tak dlouho?

Editováno 20.10.2014 15:04
Nahoru Odpovědět 20.10.2014 15:03
$action = $_GET['Life']; | Když dáš mínus, napiš proč!
Avatar
Matúš Petrofčík
Šéfredaktor
Avatar
Odpovídá na Richard
Matúš Petrofčík:

Moj testovaci apache pod win 7 (lokalne), a db postgres 9 na serveroch websupportu (nie lokalne). Taktiez niesu to len dotazy ale komplet system s generovanim sablon, routovanim atd, napisal som sam, malinko podobne tomu z tutorialov (dalsi projekt bude snad na nette alebo laraveli z dovodu, ze sa mi uz nechce riesit kazdu prkotinu ktora uz vyriesena je). Casy su podla toho za kolko ho chrome dostane vygenerovane naspat. Net je Slovenska akademicka siet. Raz som pouzival aj pocitadlo v php ale oproti casom v chrome to bolo par ms rozdiel, tak to snad aspon trochu spolahlive bude :D tie joiny su skvela vec, lebo som okrem casu usetril aj zbytocny kod :)

Editováno 20.10.2014 15:43
Nahoru Odpovědět 20.10.2014 15:41
obsah kocky = r^2 ... a preto vlak drnká
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Richard
David Čápka:

Na takováto mereni pozor, DB si děla nejake cache, takže když tu query spustis poprvé, většinou tvá jinak dlouho než podruhé a další případy jsou také mnohem rychlejší. Merit bys mel na dostatecnych datech, na 3 polozkach se nepozná nic a může to zpomalovat třeba i samotné parsovani toho příkazu :) Jestli mas chuť, vygeneruj tam par tisíc položek a hod sem casy, to uz bude zajímavé.

Nahoru Odpovědět 20.10.2014 16:08
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Martin Konečný (pavelco1998):

David Čápka, Michal Štěpánek: No vidíte, vím jak to použít, ale ani nevím, jak přesně se to jmenuje :D Děkuji za doplnění.

 
Nahoru Odpovědět 20.10.2014 16:36
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 36 zpráv z 36.