Autor | Zpráva | ||
---|---|---|---|
Ffreeman Profil * |
#1 · Zasláno: 19. 9. 2009, 17:00:26
Ahoj,
mám postgre databázi internetového obchodu, jehož schema můžete stáhnout NA TÉTO ADRESE Soustředím se především na produkt a to konkrétně na výpis katalogu. Pro tento výpis potřebuji informace z tabulek (v závorce je přibližný počet záznamů, kde znak + vyjadřuje potenciální růst): produkt (3000) produkt_translation (3000+) cena (10000+) vyrobce (80) rw_string (4670) prirazeni_poplatku (40++) poplatek (20) dan_produktu (3000) dan (3) kategorie2produkt (8000) produkt2privlastek (0+++) privlastek_produktu (10) // přívlastkem je míněno označení např. pro novinku, akci apod. Již v současnosti mám obrovské problémy s výkonem celé databáze. Aplikace je provozována na virtual hostingu a již přišly stížnosti z nadměrného vytěžování celého serveru procesem postgre (až 90 %). Brzdí to samozřejmě i celou aplikaci, která je neskutečně pomalá. Aplikace je psaná v PHP a používám ORM nástroj Doctrine. Kód v PHP vypadá zhruba takto (je tam několik IFů, ty jsem odstranil): $q->select('p.kod_produktu, t.nazev_produktu, t.charakteristika, c.kod_cs, c.kod_meny, c.hodnota_ceny, dan.vyse') ->from('Produkt p') ->leftJoin('p.Dan dan') ->innerJoin('p.Cena cena') ->leftJoin('p.Poplatek pop') ->innerJoin('p.Vyrobce vyr') ->innerJoin('p.Kategorie2produkt kat') ->leftJoin('p.PrivlastekProduktu pp') ->where('cena.kon_datum IS NULL') ->andWhere('cena.kod_cs = ?', $params['kod_cs']) ->andWhere('cena.kod_meny = ?', $params['kod_meny']) $q->andWhereIn('kat.kod_kategorie', $params['kod_kategorie']); $q->orderBy($params['orderBy'].' '.$smer); $q->limit($params['limit']); Ten posílá databázi dotazy, jako je tady tento: SELECT p.kod_produktu AS p__kod_produktu, d.kod_dane AS d__kod_dane, d.vyse AS d__vyse, p6.kod_produktu AS p6__kod_produktu, p6.lang AS p6__lang, p6.nazev_produktu AS p6__nazev_produktu, p6.charakteristika AS p6__charakteristika FROM produkt p LEFT JOIN dan_produktu d2 ON (p.kod_produktu = d2.kod_produktu) LEFT JOIN dan d ON d.kod_dane = d2.kod_dane INNER JOIN cena c ON p.kod_produktu = c.kod_produktu LEFT JOIN prirazeni_poplatku p3 ON (p.kod_produktu = p3.kod_produktu) LEFT JOIN poplatek p2 ON p2.kod_poplatku = p3.kod_poplatku INNER JOIN vyrobce v ON p.kod_vyrobce = v.kod_vyrobce INNER JOIN kategorie2produkt k ON p.kod_produktu = k.kod_produktu LEFT JOIN produkt2privlastek p5 ON (p.kod_produktu = p5.kod_produktu) LEFT JOIN privlastek_produktu p4 ON p4.id_privlastek = p5.id_privlastek LEFT JOIN produkt_translation p6 ON p.kod_produktu = p6.kod_produktu WHERE p.kod_produktu IN (SELECT doctrine_subquery_alias.kod_produktu FROM (SELECT DISTINCT p7.kod_produktu, p12.nazev_produktu FROM produkt p7 LEFT JOIN dan_produktu d4 ON (p7.kod_produktu = d4.kod_produktu) LEFT JOIN dan d3 ON d3.kod_dane = d4.kod_dane INNER JOIN cena c2 ON p7.kod_produktu = c2.kod_produktu LEFT JOIN prirazeni_poplatku p9 ON (p7.kod_produktu = p9.kod_produktu) LEFT JOIN poplatek p8 ON p8.kod_poplatku = p9.kod_poplatku INNER JOIN vyrobce v2 ON p7.kod_vyrobce = v2.kod_vyrobce INNER JOIN kategorie2produkt k2 ON p7.kod_produktu = k2.kod_produktu LEFT JOIN produkt2privlastek p11 ON (p7.kod_produktu = p11.kod_produktu) LEFT JOIN privlastek_produktu p10 ON p10.id_privlastek = p11.id_privlastek LEFT JOIN produkt_translation p12 ON p7.kod_produktu = p12.kod_produktu WHERE c2.kon_datum IS NULL AND c2.kod_cs = 'CS600001' AND c2.kod_meny = 'CZK' AND k2.kod_kategorie IN ('9675') AND (p12.lang = 'cz') AND (p7.deleted_at IS NULL) ORDER BY p12.nazev_produktu ASC LIMIT 12) AS doctrine_subquery_alias) AND c.kon_datum IS NULL AND c.kod_cs = 'CS600001' AND c.kod_meny = 'CZK' AND k.kod_kategorie IN ('9675') AND (p6.lang = 'cz') AND (p.deleted_at IS NULL) ORDER BY p6.nazev_produktu ASC Možná již někteří, kteří tento příspěvek čtou, kroutí hlavou a říkají si, proč jsem nepoužil příkaz explain. Háček je v tom, že i přes načtení mnoha materiálů, nejsem pravděpodobně schopen správě pochopit, co mi vlastně čísla znamenají. Příkaz explain analyze + předchozí dotaz naleznete ZDE (link na textový soubor) Celý dotaz lze přepsat do následujícího dotazu, který je, alespoň dle mého chápání, daleko méně náročný: SELECT p.kod_produktu,p.id_rw_string, p.kod_vyrobce, t.nazev_produktu, t.charakteristika, c.hodnota_ceny, v.nazev_vyrobce, rw.string, d.vyse, pop.poplatek FROM produkt as p INNER JOIN produkt_translation as t ON (p.kod_produktu = t.kod_produktu) INNER JOIN cena as c ON (p.kod_produktu = c.kod_produktu) INNER JOIN vyrobce as v ON (p.kod_vyrobce = v.kod_vyrobce) INNER JOIN rw_string as rw ON (p.id_rw_string = rw.id_rw_string) LEFT JOIN prirazeni_poplatku as pri ON (p.kod_produktu = pri.kod_produktu) LEFT JOIN poplatek as pop ON (pop.kod_poplatku = pri.kod_poplatku) LEFT JOIN dan_produktu as dp ON (p.kod_produktu = dp.kod_produktu) INNER JOIN dan as d ON (d.kod_dane = dp.kod_dane) INNER JOIN kategorie2produkt as k2p ON (p.kod_produktu = k2p.kod_produktu) LEFT JOIN produkt2privlastek as p2p ON (p.kod_produktu = p2p.kod_produktu) LEFT JOIN privlastek_produktu as pp ON (pp.id_privlastek = p2p.id_privlastek) WHERE c.kod_meny = 'CZK' AND p.deleted_at IS NULL AND c.kod_cs = 'CS600001' AND k2p.kod_kategorie IN ('9675') AND t.lang = 'cz' ORDER BY t.nazev_produktu ASC LIMIT 12 explain anylze + Select ... pak vypadá TAKTO (link na textový soubor) Otázkou je, jak vnutit Doctrine, aby svoje dotazy "neprznil", jak to dělá doteď. Jak tuto záležitost radikálně zrychlit? Uvažoval jsem nad nějakými dočasnými tabulkami, ale vzhledem k tomu, že je celá aplikace napsána v Doctrine, bylo by dosti těžké převést data z temporární tabulky do objektů. Další možnost, která mě napadla, je kompletní cache a to buď výstupu nebo objektů. Ta ovšem funguje pouze v případě, že člověk nevyhledává podle názvu, nefiltruje podle výrobce apod. Má někdo nějaký návrh, co s tím? Předem děkuji za jakoukoli pomoc či názor. |
||
Časová prodleva: 15 let
|
0