konto usunięte

Temat: Problem z alokacją pamięci

Witam.

Mam dość irytujący problem z CakePHP.

Dane są następujące:
- serwis WWW jest napisany w CakePHP
- PHP ma do dyspozycji 64 MB pamięci i nie da sie tego parametru zwiększyć
- cała baza danych ma około 50 MB

Problem:
- prosty SELECT z bazy danych musi być ograniczany do 1500 rekordów ze względu na przepełnienie pamięci skutkujący komunikatem:
*Fatal error*: Allowed memory size of 67108864 bytes exhausted (tried to allocate 24 bytes) in */www/cake/libs/model/datasources/dbo/dbo_mysql.php*  on line *407


W jaki sposób zapanować nad tym zjawiskiem?

Dziękuję za wszelkie podpowiedzi.

Pozdrawiam,
Robert
Tomasz Wójcik

Tomasz Wójcik inżynier informatyk,
specjalizacja: sieci
komputerowe

Temat: Problem z alokacją pamięci

1. przydzielic modelom krotsze aliasy - Cake bedzie indeksowal krotszymi tekstami ergo zajmie na aliasy (indeksy tablic) mniej ramu
2. pobierac tylko potrzebne pola
3. cache cache i jeszcze raz cache

po przekazaniu danych do widoku (Controller::set(combine('dane')); usuwac (unset) $dane; (ew. kopiowac dane do widoku petla i unset'owac po kazdej iteracji - nie bedzie dubla w RAMie, no ale wolniej)

ew. pobieranie rekordow i przetwarzanie (z cache'owaniem) na raty po 1500 rekordow z manualnym renderowaniem a nie autoRender, ktory wysysal widokowi wszystko naraz

tyle mi na o tej godzinie przychodzi do glowy, swoja droga 64MB to calkiem sporo - niezla musi byc aplikacja, albo kiepska optymalizacja ;)
pozdrawiam

konto usunięte

Temat: Problem z alokacją pamięci

Zacząłem rozkładać to wszystko na części i doszedłem po dużych skrótach do takiego skryptu PHP:


$query = "SELECT * FROM tabela";
$result = mysql_query($query);
$i=0;
while ($row = mysql_fetch_row($result)) {
$i++;
if ($i<4500) {
$table[$i] = $row;
// w tej linii następuje przepełnienie
// pamięci jeśli liczba rekordów > 4500
}
}


Tabela "tabela" ma 14000 rekordów, zajmuje w bazie danych około 6 MB.

Czyli problem tak naprawdę sprowadza się do poprawnego napisania linii

$table[$i] = $row;

aby nie było przepełnienia pamięci (64MB).

Czy może ktoś ma na to rozwiązanie?
Tomasz Wójcik

Tomasz Wójcik inżynier informatyk,
specjalizacja: sieci
komputerowe

Temat: Problem z alokacją pamięci

1. musisz pobierac wszystkie pola z bazy danych?
$query = 'SELECT id, nazwa, wartosc, ... FROM ...'

zamiast
$query = 'SELECT * FROM ...'


pobierze tylko potrzebne pola, no chyba ze musisz wyciagnac wszystkie

2. czy musisz ladowac wszystkie 14 tys rekordow do pamieci!? raczej watpie, naraz raczej nie operujesz na 14000 wierszy

3. co potem robisz z $table, gdzie to jest uzyte i do czego? wyswietlasz na stronie naraz 14000 wierszy? tez watpie :P

4. ten kod to czysty PHP, nie widze nic z CakePHP, wiec albo uprosciles albo piszesz kompletnie niezgodnie z podstawowymi zasadami MVC ... ale mam nadzieje, ze to tylko skrot pogladowy.

generalnie - odpowiedz na wszystkie pytania, a w szczegolnosci na #3Tomasz Wójcik edytował(a) ten post dnia 13.07.10 o godzinie 09:02

konto usunięte

Temat: Problem z alokacją pamięci

Tomasz Wójcik:
1. musisz pobierac wszystkie pola z bazy danych?

Tak
2. czy musisz ladowac wszystkie 14 tys rekordow do pamieci!? raczej watpie, naraz raczej nie operujesz na 14000 wierszy

Tak, potrzebuję (w pewnych sytuacjach) wszystkie rekordy.
3. co potem robisz z $table, gdzie to jest uzyte i do czego? wyswietlasz na stronie naraz 14000 wierszy? tez watpie :P

$table to wynik zapytania ujęty w tablicę. W ten sposób Cake zwraca każdy SELECT.
4. ten kod to czysty PHP, nie widze nic z CakePHP, wiec albo uprosciles albo piszesz kompletnie niezgodnie z podstawowymi zasadami MVC ... ale mam nadzieje, ze to tylko skrot pogladowy.

Ten skrót to uproszczenie całego CakePHP do podstawowego kodu PHP. Pokazanie istoty problemu.

Jak wspomniałem wcześniej, problem dotyczy CakePHP i po wielu uproszczeniach doszedłem do tego, że Cake przetwarza zapytanie do bazy właśnie w ten sposób. Powoduje to błąd alokacji pamięci. Zapytanie pochłania ponad 64 MB RAM i powoduje błąd PHP a cała tablica ma około 6 MB. Jak można to zrobić poprawnie?

Oczywiście nie ma możliwości zwiększenia przydziału pamięci dla PHP.
Tomasz Wójcik

Tomasz Wójcik inżynier informatyk,
specjalizacja: sieci
komputerowe

Temat: Problem z alokacją pamięci

jeszcze raz zapytam "co robisz potem z $table?". ja wiem ze jest to PHPowa tablica odpowiadajaca bezie danych, ale mnie sie rozchodzi o to co z nia robisz, jak ja wykorzystujesz i do czego?

wyswietlasz wszystkie wiersze na stronie?
liczysz sume jakiegos pola np. $tagle[$iteracja]['wartosc']?

czy co, bo moze podejscie masz zle w ogole, moze SQL potrafi zrobic cos co Ty probujesz zrobic w PHPie.

najwazniejsze jest sedno problemu, jak powiesz do czego potrzebujesz naraz 14 tys wierszy to sie cos wymysli, bo poki co mozesz tak:
1. pobranie 3 tysi, zserializowanie i zapisanie do pliku #1 (taki cache) i potem kolejne 3 tysie czytasz, do pliku #2 itd.
2. czytasz z cache #1, cos z nim robisz (jakies przetwarzanie) i znowu do pliku itd.
3. na koniec czytasz z pliku, wyswietlasz, zwalniasz pamiec i czytasz z kolejnego pliku itd.
no ale to kompletnie porabane podejscie imho, moze wystarczy rozbic Twoje zapytanie na kilka zapytan SQL, ktore rozwiaza Ci sprawe, no ale musisz powiedziec CO CHESZ ZROBIC.

napisz jakie sa pola w tabeli SQL, potem jak chcesz je przetwarzac (co z nimi robic, policzyc sume, zliczyc rekordy, wyswietlic 14 tys wierszy na stronie czy jeszcze cos innego), bo bez takich podstawowych informacji to gowno mozna pomoc tak naprawde, a wtedy patrz powyzsze 3 punkty mojego rozwiazania - tez sie nadaja wtedy, jak nie wiem jaki jest problem.

konto usunięte

Temat: Problem z alokacją pamięci

Tomasz Wójcik:
jeszcze raz zapytam "co robisz potem z $table?". ja wiem ze jest to PHPowa tablica odpowiadajaca bezie danych, ale mnie sie rozchodzi o to co z nia robisz, jak ja wykorzystujesz i do czego?

Jeszcze raz napiszę - uprościłem do bardzo prostego kodu PHP to, co robi z każdym zapytaniem CakePHP aby było widać mechanizm jego działania.
W $table jest wynik zapytania. Obojętne, jakie ono jest, w $table znajduje się to, co się wywołuje SELECTem z bazy danych. Podałem w jaki sposób CakePHP wpisuje do tablicy $table wartości kolejnych wierszy z zapytania i właśnie ten sposób przy tabelach o rozmiarach kilku MB powoduje przepełnienie pamięci.

Ponieważ problem dotyczy głownie CakePHP, znalazłem sporo pytań na ten temat w necie. Niestety, odpowiedzi sugerują w zasadzie ciągle to samo czyli mało wydajne rozwiązanie polegające na "pakowaniu" wyników w określone "paczki". Myślę, że jest o wiele skuteczniejsze rozwiązanie.
moze wystarczy rozbic Twoje zapytanie na kilka zapytan SQL, ktore rozwiaza Ci sprawe, no ale musisz powiedziec CO CHESZ ZROBIC.

Powtórzę - potrzebuję mieć w $table całą tabelę MySQL'a. Taka jest konieczność.
Marcin B.

Marcin B. Webdirector,
Wspólwłasciciel
Contip.net

Temat: Problem z alokacją pamięci

Robert Kozakiewicz:
Podałem w jaki sposób CakePHP wpisuje do tablicy $table wartości kolejnych wierszy z zapytania i właśnie ten sposób przy tabelach o rozmiarach kilku MB powoduje przepełnienie pamięci.
W jaki sposób doszedłeś do tego, że przy pomocy takiej prostej pętli while zapisuje do tablicy? Może jakbyś podrzucił to miejsce to można pomyśleć, jak zoptymalizować tą funkcję.
Powtórzę - potrzebuję mieć w $table całą tabelę MySQL'a. Taka jest konieczność.
A ta konieczność to?

Poza tym nawet jeśli tabela w SBD zajmuje powiedzmy te 6MB, to nie oznacza, że jak te wszystkie dane wrzucisz do tablicy asocjacyjnej w PHP to też będzie zajmowała tyle samo, ba - będzie zajmowała więcej.

Ale to nie jest problem CakePHP tylko samego PHP i tego w jaki sposób alokuje pamięć dla tablic.

Co do samego rozwiązania problemu, to całkiem możliwe, że uda się to rozwiązać przy pomocy wbudowanej w Cake klasy Cache: http://book.cakephp.org/view/1511/Cache
- wybrać jeden z silników cache'ujących w app\config\core.php, np. File storage engine co by się zapisywało na dysk, a nie do pamięci,
- i potem już odpowiednio operować Cache::write() i Cache::read(), pobierając i zapisując dane fragmentami

Jednak nawet żaden cache nie pomoże, jeśli zechcesz gigantyczną ilość danych wrzucić do tablicy w PHP - zawsze dojdziesz do momentu, że pamięci zabraknie, także kwestią jest raczej w sprytny sposób operować na danych.Marcin B. edytował(a) ten post dnia 21.07.10 o godzinie 23:51

Temat: Problem z alokacją pamięci

Czy model którego obiekty pobierasz ma powiązania z innymi? Cake domyślnie na find'a joinuje modele, ale można ustawić np.

$this->Model->recursive = -1;

wtedy pobrane zostaną dane tylko danego modelu.

więcej: http://book.cakephp.org/view/439/recursive

Następna dyskusja:

Auth Component problem




Wyślij zaproszenie do