Autor Zpráva
Prkny
Profil
Zdravím, mám dotaz v mysql který trvá neúnosných 3,5 - 5 sec. Nevím jak jej zjednodušit a prosím o pomoc.

Dotaz prochází zboží v dané kategorii a hledá DISTINCTem jedinečné názvy parametrů, které jsou právě k danému zboží v té které kategorii.

Příklad onoho dotazu:
SELECT DISTINCT pzp.nazev, pzp.id, pzp.skupina 
FROM parametry_zb p, parametry_zb_prehled pzp 
WHERE p.id_zbozi IN ( SELECT z.id FROM zbozi z, zbozi_v_kat k WHERE z.id = k.id_zbozi 
             AND z.vyradit = '' 
             AND k.id_kat IN (SELECT id FROM kategorie WHERE (lft>'888') AND (rgt<'915')) 
             ) 
             AND pzp.id = p.id_parametru 
             ORDER by pzp.nazev 

Ještě upřesím tabulky zbozi a zbozi_v_kat a kategorie jsou poměrně velké počtem záznamů.
Ale tabulky parametry_zb a parametry_zb_prehled jsou zatím prakticky prázdné a přesto to takto dlouho trvá ...

Můžete mi poradit ?
Tori
Profil
Zkuste ty poddotazy přepsat jako join:
SELECT DISTINCT pzp.nazev, pzp.id, pzp.skupina
FROM parametry_zb p
INNER JOIN parametry_zb_prehled pzp ON pzp.id = p.id_parametru
INNER JOIN zbozi z ON z.id = p.id_zbozi
INNER JOIN zbozi_v_kat k ON z.id = k.id_zbozi AND z.vyradit = ''
INNER JOIN (SELECT id FROM kategorie WHERE (lft>'888') AND (rgt<'915')) ref ON k.id_kat = ref.id
ORDER BY pzp.nazev
Možná bude někde potřeba změnit INNER na LEFT JOIN, nevím jaké jsou závislosti mezi tabulkami.
Místo SELECT DISTINCT ... ORDER BY by asi šlo použít i SELECT ... GROUP BY pzp.nazev (seřazení je implicitní), ale nevím, jestli to bude mít nějaký vliv na rychlost, vyzkoušejte.
Keeehi
Profil
Prkny:
Taky záleží na tom, zda jsou indexy nad správnými sloupci.
Prkny
Profil
Tori:
Váš dotaz razantně výsledek zrychlil, ale i přes to se dotaz provede za 0,7 sek. oproti 5 sekundám je to výborné, ale jelikož je to bude provádět na stránkách opravdu neustále asi by to chtělo ještě snížit. Pokud to vůbec ještě půjde.
SELECT... nebo DISTINCT je často prakticky stejný.... GROUP BY nebo ORDER také stejně.

Keeehi:
Indexy moc řešené nejsou... moc se v návrhu indexu nevyznám... můžete mi dát nějaký tip ?
Alphard
Profil
Prkny:
Určitě si zobrazte explain, ale obecně indexy na sloupce, podle kterých se spojuje, řadí a filtruje.
Zkusil bych je hodit na všechny sloupce, co mají v názvu id + lft, rgt a nazev.
Jakých hodnot nabývá vyradit?
Prkny
Profil
Alphard:
Parametr vyradit nabývá zatím pouze "out". Ten název je myšlen pro sloupec pzp.nazev ?
Co také indexovat k.id_zbozi ?


Alphard:
Omlouvám se teť jsem si tu větu "všechny sloupce, co mají v názvu id" přečetl lépe, takže moje otázka je bezpředmětná.
pcmanik
Profil
Prkny:
Skus spustit explain nad tym dotazom a hod sem vypis.
Prkny
Profil
Alphard, Keeehi, Tori:
Pánové mnohokrát děkuji. Chyba byla především v indexech. Nyní mi ten dotaz běhá něco za 0,0027 sek. Takže nyní naprostá spokojenost.

pcmanik:
V tom explainu jsem se nikdy nenaučil číst mohu poprosit o letmou analýzu s vysvětlením ?

http://imageshack.us/photo/my-images/401/20120722185836.jpg/
Tori
Profil
Prkny:
Jak koukám na ten explain, tak jsem tam nechala zbytečně tenhle poddotaz: INNER JOIN (SELECT id FROM kategorie WHERE (lft>'888') AND (rgt<'915')) ref ON k.id_kat = ref.id

Zkuste to změnit takhle:
INNER JOIN kategorie kat ON k.id_kat = kat.id
WHERE kat.lft > 888 AND kat.rgt < 915
ORDER BY pzp.nazev
V explainu by měla zmizet tabulka označená jako "derived", a u tabulky "kategorie" by se mělo jednak snížit číslo ve sloupci rows (=počet řádků, které je potřeba z tabulky přečíst), a sloupce key a key_len by už neměly být NULL (totiž z toho původního poddotazu si MySQL dělalo dočasnou tabulku - to je ta "derived", u které ale nemohlo využít žádné indexy. Tohle by to mělo napravit.)

U tabulky parametry_zb se nepoužívá žádný index - měly by tam být 2, na sloupcích id_parametru a id_zbozi.
Prkny
Profil
Tori:
Díky, do tabulky parametry_zb jsem indexy doplnil.

Jen pro informaci, díky vašim radám jsem se z 5 sek. dostal na 0,0028 sek.


VŠEM DĚKUJI !!!

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0