Cache výstupu komponenty BEZ opakovaného volání render() když se čte z cache
- neznamy_uzivatel
- Člen | 115
Ahoj,
cachuju celou komponentu, např:
{cache 'ahojahoj', expire => '+1 hour'}
{control egcategories}
{/cache}
Metoda render v komponentě egcategories udělá jen:
$template = $this->template;
$template->setFile(__DIR__ . 'sablona.latte');
$template->tralala = $this->database->table('egkategorie')->where('active = 1')->fetchAll();
Jak to dostat do cache? Teda přesněji – jak donutit nette, aby
v případě čtení z cache nespouštělo tu render metodu, která může x
vteřin čekat nad zamknutou tabulkou, než vypíše data? Výstup té
komponenty se sice do cache uloží a nette z toho pak i čte, nicméně
stále spouští i tu render metodu, jako by cache neměl.
Očekával bych postup
načíst z db
uložit do cache
a na hodinu zobrazovat obsah z cache
Realita je ovšem:
Načíst z db
uložit do cache
a příště:
zase načíst z db
zobrazit z cache
Snad to popisuju dobře :D
Prostě potřebuju, aby se nespouštěl kód v komponentě v případě, že
už nette načetlo předgenerovaný obsah z cache a taky ho to zobrazilo,
tudíž není třeba spouštět komponentu, jejíž výsledek se už stejně
nikde nepromítne (použijí se cache data bez ohledu na to, že se načetlo
z db něco novějšího..)
díky
ps problém už byl několikrát zmíněn, např. zde: https://forum.nette.org/…ch-jak-na-to#…
Ovšem řešení v podobě předávání tisíce závislostí a předávání
anonymních funkcí přes proměnnou do šablony mi přijde jako absurdní
šílenost :)
Editoval neznamy_uzivatel (13. 8. 2016 17:25)
- neznamy_uzivatel
- Člen | 115
- Chci, aby se to nezdrzovalo renderovanim.
- Chtel bych, aby to fungovalo jak ma. Chci to pouzit na vice mistech a prakticky lze cachovat pouze staticky obsah :D
- To co vraci Table (Selection?) cachovat pokud se neco nezmenilo primo nelze bohuzel.
To cachovani primo v sablonach by bylo krasne, super, excelentne genialni, ucinne a jednoduche… kdyby fungovalo..
- CZechBoY
- Člen | 3608
Můžeš si uložit výsledek dotazu jako pole třeba pomocí
$rows = $selection->fetchAssoc('[]->');
a řádek budeš mít pořád jako objekt(stdClass). Tohle potom můžeš cachovat.
Pokud chceš cachovat i render tak máš změřený, že to je fakt nějaký pomalý, nebo prostě chceš aby to nerenderovalo dvakrát?
- neznamy_uzivatel
- Člen | 115
Tohle vyzkouším, dík :) Pomůže mi to na jiných místech, kde mám šílené cykly, abych to celé přetáhl do pole a zacachoval :)
Jinak tenhle konkrétní případ je opravdu hodně pomalý, proto řeším, aby byl v cache celý ten html výstup. Jsou tam tisíce položek (desetitisíce dotazů napříč desítkami tabulek), php na tom stráví přes 2.5 sec.. (z toho mysql asi 250ms)
A mimo to… proste pocit, ze se neco natahlo z cache a presto se se zobrazenim ceka na funkci, ktera ty data znou nacte a zpracuje aniz by se ty nove data nekde projevily je… :D lehce neprijemny, kdyz se generovani stranky priblizuje bez cache ke trem vterinam a s cache v sablone asi na 2.95 :(
Editoval neznamy_uzivatel (13. 8. 2016 17:00)
- Spectator
- Člen | 48
neznamy_uzivatel napsal(a):
Tohle vyzkouším, dík :) Pomůže mi to na jiných místech, kde mám šílené cykly, abych to celé přetáhl do pole a zacachoval :)
Jinak tenhle konkrétní případ je opravdu hodně pomalý, proto řeším, aby byl v cache celý ten html výstup. Jsou tam tisíce položek (desetitisíce dotazů napříč desítkami tabulek), php na tom stráví přes 2.5 sec.. (z toho mysql asi 250ms)
A mimo to… proste pocit, ze se neco natahlo z cache a presto se se zobrazenim ceka na funkci, ktera ty data znou nacte a zpracuje aniz by se ty nove data nekde projevily je… :D lehce neprijemny, kdyz se generovani stranky priblizuje bez cache ke trem vterinam a s cache v sablone asi na 2.95 :(
V tom případě je problém asi jinde :-) 3s je dost … MOC
- neznamy_uzivatel
- Člen | 115
3s je dost málo na to množství dat… (jiné scripty mi běží i několik hodin – mám v db dohromady něco přes 20 mil. řádků) Proto je tohle všechno v backendu a výstupem má být HTML do cache, kde se nic hodinu nemá měnit.
Každopádně nechápu ten problém s cache. Jak se zdá nedělá to všude. Právě jsem to vyzkoušel na jiném serveru a vypadá to, že se ta render metoda spouští opravdu jen při generování cache.
///
Už je to docela zmatené tady :D
Prostě je to složité, generuje se HODNĚ dlouhý výstup z opravdu VELKÉ
databáze a je potřeba použít efektivní cache. Vzholedem k tomu, že se to
na jiném serveru chová jinak, tak užn fakt nevím. Mám na to jednoduchý
testovací kód a zcela náhodně se mi na některých serverech ta render
metoda zavolá a jinde, nebo jindy zase ne..
Editoval neznamy_uzivatel (13. 8. 2016 17:24)
- Spectator
- Člen | 48
CZechBoY napsal(a):
Ty vypisujes celou databazi? Vsech 20M radku?
Deset tisic dotazu pri nacteni jedny stranky?
Specifikuj spis kde mas bottleneck :-) zkus nejakej profiler, treba blackfire.
Přesně tak, brzdí ti to něco zbytečného v kódu. 20 mil. řádků v dtb. není nic hrozného. Běžně se pracuje s tabulkami o stovkách mil. záznamů.
- Martk
- Člen | 661
Data se ti načítají i po keši, protože fetchAll pošle dotaz do mysql a nette/database to zpracuje, bez ohledu na to, zda-li to použiješ.
Můžeš udělat tohle:
class Lazy implements IteratorAggregate {
private $callback;
public function __construct(callable $callback) {
$this->callback;
}
public function getIterator() {
$callback = $this->callback;
return new ArrayIterator($callback());
}
}
Rozdíl už je potom jen v presenteru:
$template = $this->template;
$template->setFile(__DIR__ . 'sablona.latte');
$template->tralala = new Lazy(function () {
$this->database->table('egkategorie')->where('active = 1')->fetchAll();
});
Klidně můžeš vynechat i tu anonymní funkci a předávat Selection a v Lazy volat fetchAll.
Editoval Antik (13. 8. 2016 18:08)
- David Matějka
- Moderator | 6445
@Antik ale ten fetchAll ma umisteny v render metode komponenty a cachuje cele vykresleni komponenty, takze by se to provadet nemelo. problem bude nekde jinde..
- neznamy_uzivatel
- Člen | 115
CZechBoY: Nevypisuju celou db, ta komponenta je něco jako menu s kategoriema. Vypisuje se jen část dat v závislosti na dalších tabulkách. Kód uvádělý na začátku je jen ukázka, kterou jsem zkoušel mimo ten projekt, abych si byl jistý, že se to takhle chová i jinde. Jinak používám xdebug, blackfire neznám..
Spectator: 100 mil. záznamu v jedné tabulce v MySQL je už opravdu velice nepříjemná práce. V reálu na frontendu používám sphinx – v tak velké tabulce je naprosto nemyslitelné rozumě filtrovat/vyhledávat, hlavně když tam mám desítky možných filtrů a potřebuju facety.
Antik: Tak tomu vůbec nerozumím :)
Pokud správně chápu, má to fungovat tak jak jsem očekával – pokud tu
komponentu hodím v šabloně do {cache}, tak by se dotaz v render té
komponenty neměl provést. V tom případě je buď bug v nette, nebo ve mě.
Takže jdu hledat co jsem pokazil :)
Nejhorší je, že to neudělá pokaždé. Dal jsem si logovat každé
spuštění toho renderu a je to opravdu náhodné. z 10ti refreshů se někdy
spustí jednou, někdy 3×, někdy 10x…
Editoval neznamy_uzivatel (13. 8. 2016 18:45)