Autor | Zpráva | ||
---|---|---|---|
Toníček Profil * |
#1 · Zasláno: 14. 11. 2018, 14:34:50
Dobrý den,
Měl bych dotaz s optimalizací rychlosti načítání dat, nejsem databázově. mám cca 7 tabulek s produkty, a potřebuji vyhledat např. produkty pokud jsou skladem, jestli jsou v této kategorii atd. nebo jestli jsou neoemzené (níže posílám aktuální příkaz). Mám nastavené indexy (id je primary key / auto_increment) index je product_id, na všech tabulkách. Jakmile se snažím ale připojit kategorii, první dotaz (při 5 000 produktech) trvá 7 sec, poté další (ten stejný) asi cache je 0,00004s, ...za minutu pouštím znova a opět čekat (nebo pokud změním příkaz). Dokáže mi někdo poradit, jak lépe optimalizovat? $kategorie = 102; SELECT pr.* FROM produkty pr LEFT JOIN produkty_jazyk prl ON pr.id = prl.product_id LEFT JOIN produkty_kategorie cat ON pr.id = cat.product_id LEFT JOIN produkty_sklad stock ON pr.id = stock.product_id OR pr.id = stock.product_parent_id WHERE pr.parent_id=0 AND pr.deleted=0 AND cat.category_id=$kategorie AND (stock.amount>0 OR stock.unlimited=1) GROUP BY pr.id ORDER BY pr.price ASC LIMIT 60, 15 Pro upřesnění skladu - řeším z důvodů variant (př. je skladem jen nějaká varianta u toho produktu, tak je potřebuji projít.): LEFT JOIN produkty_sklad stock ON pr.id = stock.product_id OR pr.id = stock.product_parent_id Toto zase určuje sklad (větší než 0 nebo neomezený) AND (stock.amount>0 OR stock.unlimited=1) Díky za rady |
||
Keeehi Profil |
#2 · Zasláno: 14. 11. 2018, 15:09:55
Jaký je explain dotazu?
|
||
Kajman Profil |
#3 · Zasláno: 14. 11. 2018, 15:10:42
Pro ladění je vhodné používat
select SQL_NO_CACHE pr.*... Obecně indexy by měly být na sloupcích, podle kterých se filtruje, spojují tabulky, někdy i řadí. Někdy pomůže příkaz explain select ... |
||
Toníček Profil * |
Díky, teď jsem zjistil, že pokud odeberu
"LEFT JOIN produkty_sklad stock ON pr.id = stock.product_id OR pr.id = stock.product_parent_id " Trvá příkaz cca 0.4s, pokud ho nechám, trvá cca 7s. Jenže já potřebuji najít jen produkty, které jsou skladem (a to může být např. jen 1 varianta z 50) |
||
Keeehi Profil |
#5 · Zasláno: 14. 11. 2018, 15:14:40
Toníček:
Na product_parent_id je také index? |
||
Toníček Profil * |
Ano
Takže problém je nyní v tomto "OR pr.id = stock.product_parent_id" ale index tam je, sakra :D ![]() Teď mě to napadlo rozdvojit. LEFT JOIN produkty_sklad stock ON pr.id = stock.product_id LEFT JOIN produkty_sklad stockV ON pr.id = stockV.product_parent_id a WHERE ...AND ((stock.amount>0 OR stock.unlimited=1) OR (stockV.amount>0 OR stockV.unlimited=1) ) myslíte že je to takto ok? |
||
Kajman Profil |
#7 · Zasláno: 14. 11. 2018, 15:34:58
Když použiteje příkaz
show create table `tabulka` Explain asi také raději textově, pidi obrázky se dobře nečtou. |
||
Toníček Profil * |
#8 · Zasláno: 14. 11. 2018, 15:49:04
Teď už to jde super, jak jsem psal - napojil jsem tam 2 tabulky na místo "OR" v joinu skladu..
Ještě si s tím budu hrát. |
||
Toníček Profil * |
Zdravím,
Nyní mi ale nastal jiný problém. Potřebuji seřadit produkty podle toho, kolik jich je skladem, a to vč. variant :D Mám to takto, ale opět slow :( Nyní to asi nebere index, protože to vyhledávání PRODUCT_ID OR PRODUCT_PARENT_ID PS - předešlý problém jsem jak jsem psal ,vyřešil SELECT pr.*, ( SELECT SUM(prstock.amount) FROM produkty_sklad prstock LEFT JOIN produkty_sklad npr ON prstock.product_id=npr.id WHERE npr.deleted=0 AND (prstock.product_id=pr.id OR prstock.product_parent_id=pr.id) ) as total_stock FROM produkty pr LEFT JOIN produkty_jazyk prl ON pr.id = prl.product_id LEFT JOIN produkty_kategorie cat ON pr.id = cat.product_id WHERE pr.parent_id='0' AND pr.deleted='0' AND pr.del=0 GROUP BY pr.id ORDER BY total_stock ASC LIMIT 0, 20 pardón, takto SELECT pr.*, ( SELECT SUM(prstock.amount) FROM produkty_sklad prstock LEFT JOIN produkty npr ON prstock.product_id=npr.id WHERE npr.deleted=0 AND (prstock.product_id=pr.id OR prstock.product_parent_id=pr.id) ) as total_stock FROM produkty pr LEFT JOIN produkty_jazyk prl ON pr.id = prl.product_id LEFT JOIN produkty_kategorie cat ON pr.id = cat.product_id WHERE pr.parent_id='0' AND pr.deleted='0' AND pr.del=0 GROUP BY pr.id ORDER BY total_stock ASC LIMIT 0, 20 |
||
Kajman Profil |
Můžete si spočítat množství na skladě a to teprve připojit. Pokud to není omezené kategoríí a je potřeba sečíst skoro všechno, bývá to rychlejší než dělat tolik poddotazů na součet, kolik je produktů.
SELECT pr.*, Coalesce(prstock.amount,0)+Coalesce(t.soucet_variant,0) total_stock FROM produkty pr LEFT JOIN produkty_sklad prstock prstock.product_id=pr.id LEFT JOIN ( SELECT prstock_var.product_parent_id, sum(prstock_var.amount) soucet_variant FROM produkty_sklad prstock_var JOIN produkty pr_var ON prstock_var.product_id=pr_var.id WHERE pr_var.deleted=0 GROUP BY prstock_var.product_parent_id) t ON pr.id=t.product_parent_id WHERE pr.parent_id='0' AND pr.deleted='0' AND pr.del=0 ORDER BY total_stock DESC LIMIT 0, 20 Ale musí se projít na disku a posčítat všechny řádky, tak to bude pomalé. Pokud je u této sestavy důležitá rychlost, je možné si udělat pomocný sloupec nebo pomocnou tabulku, kde se bude upravovat množství i při změně potomka. Také by rychlosti mohlo pomoci, kdyby se smazané věci přesouvaly do jiných tabulek a v těch pro výpočty byly jen aktuální produkty a podprodukty. EDIT: v tom poddotaze jsem doplnit inner join na produkty s testem, že podprodukt není smazaný. Left join v [#9] ale smazané neomezoval. |
||
Časová prodleva: 5 let
|
0