Podivné chování cache a database
- David Růžička
- Člen | 43
Narazil jsem na zvláštní problém při použití Nette\Database, související zřejmě s kešováním a optimalizací dotazů do db.
Následující kód normálně bez problémů funguje, vypíšou se položky z db (před spuštěním je dobré vymazat cache, abychom začínali za stejných podmínek):
//----skript1-----
$items = $database->table('dbTableName');
$arr = array();
foreach($items as $item)
{
$arr[] = $item;
}
foreach ($arr as $arrayItem)
{
dump("$arrayItem->id $arrayItem->name");
}
přeukládání do pole je tu zbytečné, ale v mém případě jsem to potřeboval a chyba se vyskytne právě jen když to přeuložím do pole.
Chybu lze navodit takto:
Pokud vymažu cache a ihned zavolám následující skript (skript2), pak už
předchozí příklad nebude nadále fungovat a bude hlásit ‚Cannot read an
undeclared column „name“‘ (skript1 se ale nesmí volat ze stejné stránky
hned po skript2, protože pak to z nějakého důvodu funguje. Musí to prostě
být dvě oddělené zobrazení stránky)
//----skript2-----
$items = $database->table('dbTableName');
dump($items->count());
Je možné, že jsem narazil na nějakou chybu? Nebo něco dělám špatně? Používám Nette 2.0.1 (29.2.2012)
- David Růžička
- Člen | 43
hrach napsal(a):
- vyzkoušej nightly, jestli to tam taky nefunguej
- plus jaky se při chybě vola dotaz v prvnim skriptu?
diky, H
Takže potvrzuji, že se to chová stejně i v nejnovější verzi: nette-v2.0–99-g064ddb0
skript1 s čerstvě vymazanou keší volá tento dotaz (v tomto případě žádný problém):
SELECT * FROM `category`
skript2 s čerstvě vymazanou keší volá stejný dotaz (také žádný problém):
SELECT * FROM `category`
následné volání skript1 (další http request), už bez vymazání keše, volá tyto dotazy:
SELECT `id` FROM `category`
SELECT * FROM `category`
řádek s dump v tomto případě vyvolá výjimku: Cannot read an undeclared column „name“
- Glottis
- Člen | 129
hola, mam take jedno podivne chovani, kteremu nerozumim a kdo vi jestli to
nesouvisi.
mam dve tabule provazane pres FK. vse funguje, i dotahovani hodnot z cizi
tabulky ale jen do doby kdy dotoho zatahnu razeni podle sloupce ukazujici do
druhe tabulky (ciselnik). povede se presne kazde druhe zobrazeni stranky.
v mysql query logu pak vidim toto
120309 12:23:26 145 Connect
145 Query SET NAMES 'utf8'
145 Query SET time_zone='+01:00'
145 Query SELECT COUNT(*) FROM `log_dhcp`
145 Query SELECT COUNT(*) FROM `log_dhcp`
145 Query SELECT `log_dhcp`.`id`, `log_dhcp`.`time`, `log_dhcp`.`dhcp_type`, `log_dhcp`.`mac`, `log_dhcp`.`ip`, `log_dhcp`.`if`, `log_dhcp`.`unknown_id` FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` ASC LIMIT 25 OFFSET 0
145 Query SELECT `log_dhcp`.* FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` ASC LIMIT 25 OFFSET 0
120309 12:23:27 145 Quit
tohle se nepovede, prestoze vsechny dotazy dopadnou dobre (ale uz se nedotahuje ta cizi hodnota a proto to asi zhavaruje)
120309 12:23:29 146 Connect
146 Query SET NAMES 'utf8'
146 Query SET time_zone='+01:00'
146 Query SELECT COUNT(*) FROM `log_dhcp`
146 Query SELECT COUNT(*) FROM `log_dhcp`
146 Query SELECT `log_dhcp`.`id`, `log_dhcp`.`time`, `log_dhcp`.`dhcp_type`, `log_dhcp`.`mac`, `log_dhcp`.`ip`, `log_dhcp`.`if`, `log_dhcp`.`unknown_id`, `log_dhcp`.`unknown` FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` DESC LIMIT 25 OFFSET 0
146 Query SELECT `log_dhcp`.* FROM `log_dhcp` LEFT JOIN `unknown` ON `log_dhcp`.`unknown_id` = `unknown`.`id` ORDER BY `unknown`.`value` DESC LIMIT 25 OFFSET 0
120309 12:23:30 146 Query SELECT `id`, `value` FROM `unknown` WHERE (`unknown`.`id` IN (2))
146 Quit
toto kliknuti na razeni naopak projde, prestoze prni dotaz po count(*) nemuze
projit. select chce sloupec log_dhcp
.unknown
a ten tam
neni. data ovsem ziskaji dalsi prikazy uz dobre a tabulka se naplni. taham to
ajaxem do dataTables. kdyz za akci zatahnu rucne, ladenka vyhodi chybu
Notice
Undefined offset: 2964
a zasekne se tu
foreach ($dhcp_log->limit($limit, $from) as $log) {
$row = array();
$row[] = "".$log->time;
$row[] = $log->dhcp_type;
$row[] = $log->mac;
$row[] = $log->ip;
$row[] = $log->if;
$row[] = $log->unknown->value; //tady se ladenka zasekne
$output['aaData'][] = $row;
}
je to chyba? nebo mam neco ja spatne? ale uz me nenapada absolutne co. nette mam posledni, tedy asi tyden stare
dik
- echo
- Člen | 134
Připojuji se.
{foreach $article->related('articles_categories')->limit(5) as $articles_categories}
<a href="{link ':Admin:Categories:info', id => $articles_categories->categories->id}" class="btn btn-mini btn-primary">{!$articles_categories->categories->title}</a>
{/foreach}
{if $article->related('articles_categories')->count() > 5}
<a href="{link ':Admin:Articles:info', id => $article->id}">...</a>
{/if}
Problém je při vytváření cache. Když je přítomna poslední podmínka v kódu, čili ->count(), tak se do cache nezapíše přítomnost sloupce categories_id, a při následném refreshi to celé padne chybou Cannot read undeclared column.
Když při vytváření cache nevolám ->count(), cache se zapíše korektně a k chybám nedochází ani při pozdějším doplnění oné podmínky.
Zkoušel jsem jak verzi 2.0.1 tak i nejnovější z github.com a bug je přítomen v obou verzích.
- Filip Procházka
- Moderator | 4668
Související https://forum.nette.org/…ache-sloupcu, možná?
Editoval HosipLan (16. 3. 2012 23:57)
- hrach
- Člen | 1838
@echo: motas tu nekolik veci dohromady a tezko se pak vyznat.
$article->related('articles_categories')->limit(5)
a$article->related('articles_categories')->count() > 5
je blbost. Pokud v sql olimitujes vysledek, tak pak dostanes vzdy max. 5 radku. Metoda count() spocita vracene radky, takze nikdy nemuze byt ta podminka splnena.- nenapasal jsou celou chybu. Kterej column to pak pri cteni nemuze najit? To mam vestit z koule?
- vubec nechapu souvislost s ref acticles v poslednim postu.
Zaloz nove vlakno (pro kazdy problem), pridej verzi nette (zkus posledni), pridej kus kodu a vypis ladenky.
- David Růžička
- Člen | 43
Nainstaloval jsem Nette 2.0.2 a příklad, který jsem uváděl na začátku, v něm už funguje. Nicméně jsem narazil na velmi podobný kód, který stále chybu vyvolává:
Následující kód normálně bez problémů funguje, vypíšou se položky z db (před spuštěním vymazat cache):
//----skript1-----
$items = $database->table('dbTableName')->where('id > 1');
$arr = array();
foreach($items as $item)
{
$arr[] = $item;
}
foreach ($arr as $arrayItem)
{
dump($arrayItem->name);
}
přeukládání do pole je tu zbytečné, ale v mém případě jsem to potřeboval a chyba se vyskytne právě jen když to přeuložím do pole.
Chybu lze navodit takto:
Pokud vymažu cache a ihned zavolám následující skript (skript2), pak už
předchozí příklad nebude nadále fungovat a bude hlásit ‚Cannot read an
undeclared column „name“‘ (skript1 se ale nesmí volat ze stejné stránky
hned po skript2, protože pak to z nějakého důvodu funguje. Musí to prostě
být dvě oddělené zobrazení stránky)
//----skript2-----
$items = $database->table('dbTableName')->where('id > 1');
dump($items->count());
Od původního příkladu se to liší tou podmínkou where. Pokud
tam ta podmínka není, kód funguje.
Dále jsem zjistil, že kód funguje i v případě, kdy místo volání
count() bez argumentů volám ve druhém skriptu count(‚id‘).
- keff
- Člen | 12
+1, díky za minimální test case – řeším stejný problém, projevuje
se jen při současném přístupu různých stránek (v mém případě
dlouhoběžící skripty odesílající newslettery).
Prozatím jsem vypnul cache – Conncetion.php:
<?php
public function setCacheStorage(Nette\Caching\IStorage $storage = NULL)
{
$this->cache = $storage ? new Nette\Caching\Cache($storage, 'Nette.Database.' . md5($this->dsn)) : NULL;
// abdoc HACK!!!!
$this->cache = null;
return $this;
}
?>
- vvoody
- Člen | 910
Taktiez mam problem s cache / count na selection.
„2.0“
„013c8ee released on 2012–02–03“
aj
„2.1-dev“
„b8ca5b8 released on 2012–04–06“
Ladenka hlasi: Notice – Undefined offset: nejake_cislo
File: Nette\Database\Table\Selection.php
Line: 763
niekedy aj iny riadok, ale vzdy ide o pristupovanie k $this->data[nejake_cislo]
- po zmazani cache prvy request ok, dalsie uz vybehne ladenka
- po vypnuti cache v Nette\Database\Connection ide vsetko ok
- po zapnuti cache v Nette\Database\Connection (cache nebola premazana) vybehne ladenka hned
- po odstraneni count() na objekt Nette\Database\Table\Selection (cache zapnuta a stale nepremazana) ladenka stale zostava svietit
- po premazani cache (je stale zapnuta) ide vsetko ok aj po opakovanom refresni, len bez toho count ktory mi treba pre inicializaciu paginatora.
Z toho mi vyplyva, ze asi nieco spojene s
<?php
public function count($column = ''){
...
?>
v Nette\Database\Table\Selection „prasi“ obsah cache, takze zatial tiez vypinam cache.
- hrach
- Člen | 1838
Prosim kdokoliv s problemy, vyzkousejte tuto verzi: https://github.com/…-refactoring
- edke
- Člen | 198
hrach wrote:
Prosim kdokoliv s problemy, vyzkousejte tuto verzi: https://github.com/…-refactoring
Kedze v poslednej verzii 2.0.4 mam tiez problemy s cachovanim pouzivanych stlpcov, skusil som tvoj fork, bohuzial v nom mi zas nefunguje spravne schema.table v Postgre, pricom samozrejme zas toto funguje korektne v 2.0.4:
SELECT *
FROM "role.user_default"
WHERE ("id" = ?)
V 2.0.4 je to spravne:
SELECT *
FROM "role"."user_default"
WHERE ("id" = ?)