Newsgroup: it.comp.www.php
Titolo: ottimizzazione algoritmo

Ho una base di dati contenente 3100 articoli, a 1740 dei quali è 
associata una immagine memorizzata sul file system.
Ora volevo creare un catalogo stampabile in PDF sfruttando FPDF.
la struttura del db è la seguente (omettendo i campi inutili)
articolo(cod, cod_cat, cod_per, cod_rep, etc.)->(alias A)
categoria(cod, descrizione, etc.)->(alias C)
reparto(cod, tipo, età, etc.)->(alias P)
periodo(cod, stagione, anno, etc.)->(alias R)
ora il catalogo lo vorrei strutturare nel modo seguente:
Per ogni periodo P contenente almeno un articolo,
-Per ogni reparto R contenente almeno un articolo del periodo P,
--Per ogni categoria C contenente almeno un art. del rep. R e periodo S,
---Stampa tutti gli articoli A che soddisfino P, R, C.
ho fatto una cosa simile (l'algo che vorrei ottimizzare - qui lo posto 
per brevità in pseudo-codice):
PrintContent() //funzione che stampa il tutto, richiamando le altre fnz
{
  //seleziono tutte le stagioni con almeno un articolo
  select cod,stagione,anno from P, A where P.cod=A.cod_per;
  //per ogni stagione del risultato
  while $res=fetch_row(query)
   {
    Stampa sul PDF "$res[stagione] $res[anno]";
    //chiama la funzione PrintReparto con il codice del periodo
    PrintReparto($res[cod]);
   }
}
PrintReparto($periodo)
{
  //seleziono tutti i reparti con almeno un articolo nel periodo passato 
per parametro
  select cod,tipo,età from A,P,R where P.cod=A.cod_per and 
R.cod=A.cod_rep and P.cod=$periodo;
  //per ogni reparto che abbia almeno un articolo del periodo $periodo
  while $res=fetch_row(query)
   {
    Stampa su PDF"$res[tipo] $res[età]";
    //chiamo PrintCategoria
    PrintCategoria($periodo,$res[cod]);
   }
}
PrintCategoria($periodo,$reparto)
{
  //seleziono tutti le categorie con almeno un articolo nel periodo e 
nel reparto passati per parametro
  select cod,descrizione from A,P,R,C where P.cod=A.cod_per and 
R.cod=A.cod_rep and C.cod=A.cod_cat and P.cod=$periodo and R.cod=$reparto;
  //per ogni categoria che abbia almeno un articolo del periodo $periodo 
e del reparto $reparto
  while $res=fetch_row(query)
   {
    Stampa su PDF"$res[descrizione]";
    //chiamo PrintArticolo con parametri $periodo, $reparto e $categoria
    PrintArticolo($periodo,$reparto,$categoria);
   }
}
PrintArticolo($periodo,$reparto,$categoria)
  {
   seleziono tutti gli articoli con periodo=$periodo, reparto=$reparto e 
categoria=$categoria
   per ogni articolo selezionato, se ha la foto la stampo, se non ce 
l'ha stampo solo la descrizione.
}
Il fatto è che un approccio che mi sembrava elegante e raffinato si 
rivela mostruosamente lento, nel senso che supera di troppo il timeout 
imposto da PHP. In effetti a riguardare il tutto, il numero di query che 
l'algoritmo esegue cresce in modo esponenziale, quindi dovrei cambiare 
direttamente l'approccio al problema, passando da una strategia 
bottom-up ad una top-down. Prima di cambiare il tutto e perdere la 
capoccia di nuovo, avete in mente qualche ottimizzazione che potrei fare 
a questo algoritmo per renderlo più efficiente ?
Spero di non avervi annoiato.
Saluti
Alesi_27

 Spero di non avervi annoiato.
eh, per essere sicuro di non annoiarmi non ho letto il tuo codice ;)
però un approccio differente potrebbe essere quello di mantenere il tuo 
attuale script per generare il catalogo PDF ad intervalli regolari (ogni 
X ore), e non "al volo".
magari metti lo script nel "cron" (se hai il server unix..)
ciao

}
Non che sia un espertone, ma non ti conviene fare tre cicli annidati?


in realtà è proprio quello che avviene, solo che gli annidamenti li ho 
fatti tramite chiamate a funzione
ciao
Alesi_27


:Provate a guardare gli ingredienti del famoso Labello che si usa per
:le labbra screpolate: Butirrospermum Parkii (sperma di maiale).

 Leonardo SE&O
ottima idea...
In realtà ciò che cambia spesso sono gli articoli, mentre stagioni 
reparti e categorie sono abbastanza statiche
ciao
Alesi_27

 a questo algoritmo per renderlo più efficiente ?
Guarda, se i campi sono davvero molti, l'unica cosa che puoi fare è far 
aspettare di più il server prima di fargli dare il timeout.
Per fare questo, gli puoi mandare, chessò, ogni 30 secondi un header 
fasullo, così che riazzeri il tempo di timeout... Dovrebbe funzionare!
Potresti farlo così: metti all'inizio di tutte le funzioni una variabile 
tipo:
$time0 = time();
dopodiché in ogni ciclo while ci metti una roba tipo:
$time1 = time();
if ($time1 >= $time0 + 30) {
	$time0 = $time1;
	header('X-pmaPing: Pong');
}
Dovrebbe poter funzionare, provalo!
 
-- 
Liuk (lo Steccalecca) - Cavaliere Jedi - Ex allievo della maestra Alkaid
Home Page: 
http://www.fanwars.it
 - Email: 
li...@fanwars.it
"Non vengo da Piacenza per piacervi, né da Lodi per lodarvi:
vengo da Chiavari..."