Nextras/ORM, pomalé načítání
- Skřetík
- Člen | 11
Mám takový větší problém s nextras/orm. Konkrétně jde o e-shop. V okamžiku kdy pracuju na běžném zobrazování stránek atd., vše letí jak raketa. Problém je okamžik, kdy potřebuji např. feed pro heureku – tedy vylistovat všechny produkty, přes vazbu (manufacturer_id → manufacturer.id) zjistit název výrobce atd.
Pokud dám nějaký limit, např. pouze 100 záznamů, je to pohoda. Jenže jak záznamy narůstají, začne se zvyšovat časová náročnost, takže rozdíl času mezi záznamy 5000 a 5100 záznamů trvá třikrát déle než těch prvních 100 záznamů atd. Při 15k záznamů už je to tak zlé, že service která to obstará přes connection->query s joinem to zvládne za zhruba 20 sekund, zatím co ORM na tom zdechne na 15 minut. Což je nepoužitelné.
Je nějaká cesta jak z toho ven? Vykašlat se při podobných metodách na ORM? Vymazat identityMap zřejmě nejde (předpokládám že je to to co zdržuje a způsobuje, že každý další záznam zabere „o trošičku víc“ času než předchozí), předpokládám že to by mohlo pomoct. Unset entity mi nijak nepomohl (v paměti pořád zůstávala).
- Polki
- Člen | 553
Momentálně se dlouhá doba odezvy různých ORM systémů řeší v mém příspěvku :D
Pokud můžu poradit já, tak doporučuji pro toto dokud se to nevyřeší ORM vůbec nepoužívat.
Mě ale bylo řečeno, že vůbec s ORM neumím pracovat a pomalost je jen má chyba. Tak možná se někdo další ozve a poradí.
- Mysteria
- Člen | 797
Jako první bych se podíval kolik to celkem pokládá dotazů, jestli tam taky nemáš nějaký problém typu vytáhnu jedním dotazem 1000 řádků a pak pro každý volám další SELECT, takže celkem jich mám 1001. Nicméně na vybrání 100 záznamů je i těch 20 vteřin šíleně moc, neznám strukturu a počet dat, ale pokud se tu nebavíme o desítkách milionech záznamů tak to musí být v řádu desítek až stovek milisekund (v případě použití dobrých indexů).
- Polki
- Člen | 553
Mysteria napsal(a):
Nicméně na vybrání 100 záznamů je i těch 20 vteřin šíleně moc, neznám strukturu a počet dat, ale pokud se tu nebavíme o desítkách milionech záznamů tak to musí být v řádu desítek až stovek milisekund (v případě použití dobrých indexů).
Dobrá myšlenka, ale nejspíš si nepochopil co psal :) Psal, že na 100 záznamech je to pohoda, a že na 20s to skočí až při 15000 záznamech a při stejných 15 tisici záznamech to s ORM trvá 15 minut.
Podle mě tam nějaká podobná bota jako s taháním pro každý řádek další SELECT bude, jelikož je ligické, že o takové věci by se měla starat databázová vrstva a ne, že by se tím měl programátor posunout zase zpátky do dob, kdy používal php funkce MySQLi funkce a vše si psát sám.
edit
select * from product
na 25000 záznamech přímo v db mi trval 0.0013s což je o dost míň, než
20s otázkou je, jaké další joiny tam jsou.
ovšem to nic nemění na tom, že když člověk napíše tupě stejné dva dotazy jak v jednom (orm), tak v druhém (notorm) a vidí, že v orm je to 45* pomalejší, a proto, že neudělal věci, které by v základu měla dělat sama databázová vrstva, tak si myslím, že entity jako objekty neobjekty, ale nebudu jen kvůli používání objektů vyvíjet 2× déle a ještě platit 2× silnější stroje jen abych si mohl říct hej sem borec entity z db mám jako objekty.
Editoval Polki (30. 7. 2019 17:57)
- hrach
- Člen | 1838
Zaklad je to prochazet postupne a pak vzdy model vyclearovat. Je k tomu neco primo v doc: https://nextras.org/…cs/3.1/model#…
- Polki
- Člen | 553
hrach napsal(a):
Zaklad je to prochazet postupne a pak vzdy model vyclearovat. Je k tomu neco primo v doc: https://nextras.org/…cs/3.1/model#…
Počkej, to musím i ručně mazat data z paměti? Neměl by se o to starat garbage colector?
- David Matějka
- Moderator | 6445
@Polki snad všechna ORM používají identity map, aby správně fungovaly.
- Skřetík
- Člen | 11
@Polki, @Mysteria: tyhle potíže při normálním zobrazení webu vůbec nenastávají. Jde o to, že u e-shopu se to prostě stává, protože je tam pár vazeb (záznam x kategorie, záznam x tabulka cen, záznam x obrázky, záznam x výrobce atd., záznam vs varianta produktu, související, alternativní produkt atd.) a nastává tam to co normálně moc ne:
- synchronizace dat -ie načtu data z xml/služby, a pak ke každému
záznamu ze zdroje musím načíst data „u mě“, a případně přepsat
změny a případně uložit, pokud se liší. Už samo o sobě je tohle
drobná nepříjemnost, protože nemůžu dělat např.
$target->title = $source->title
, protože i($targetEntity->title === $source->title)
se bohužel nastaví že$target->isModified('title')
, a tedy i$target->isModified()
, takže bych nesmyslně persistoval stejné záznamy. A k tomu refreshování identityMap znamená, že v okamžiku kdy flushnu persistnuté je prostě ten čas (flush – předchozí flush) o něco větší. Výsledek je, že jsem musel flushovat po 1 záznamu. Tam pak je zas problém, že nemůžu načíst všechny target entity, protože každý flush by mi refreshl identityMap na všech záznamech atd. Tady je vyloženě situace kdy$source->id === $target->id
je cesta do pekla právě kvůli identity mapě a refreshi - generování feedů – opět, kvůli vazbám. Problém je, že i tady to začne být po nějakém čase prostě k nepoužití. Prostě jak ten feed roste a roste, začnou se dít nějaké psí kusy na pozadí (zřejmě kvůli nutnosti držet vše v paměti a řešit jestli např. výrobce je třeba načíst nebo už je v identity mapě atd.) Nejvíc to zabíjí samozřejmě ta vazba na ceny což znamená další mega cucek v paměti – ty v zásadě vůbec nepotřebuju jako entity, ale ta hydratace tam proběhne. Když jsem si hrál trošku s microtime() přišlo mi, že každá další hydratovaná entita požere trošku víc času než ta před ní. A zase o něco méně než ta další… on je to fous, jenže na tom množství záznamu to prostě později začne sakra hrát roli. Zvlášť když je to entita o ~10ti vazbách, pár virtuálních properties atd.
Garbage collector se o to možná postará, ale já to potřebuju řešit už při generování feedu, ne až dojede skript – který je pomalý právě kvůli zřejmě hydrataci entit a identity mapě. Ale možná se pletu. Výsledek je každopádně jasný – bud dělám něco zásadně špatně, nebo prostě pro tenhle typ použití je lepší přesně ten přístup pospojovat si ty tabulky co potřebuju ručně, a ten feed vygenerovat bez ORM – sice je to krok stranou, ale to násobně rychlejší generování prostě za to stojí. Zkusím si hrát ještě s tím clearem (tam je zas otázka jestli při clearování nebudu narážet na to, že se mi budou pořád znovu načítat tabulky z vazby – ie výrobců je třeba jen 100, produktů 15k …)
Editoval Skřetík (8. 8. 2019 13:45)