Newsgroup: it.comp.www.php
Titolo: Domanda su IF annidati e velocità parsing file testo o csv

Sto facendo un piccolo programmino in php che mi passa un file csv e in
base a delle condizioni IF annidate mi inserisce valori di stringe in
varie tabelle in un database.
Il meccanismo funziona ma la velocità di esecuzione per un file ad
esempio di 67k è di circa 3 secondi, un po' tanto mi sembra. Secondo
voi come potrei velocizzare una operazione di questo tipo ? Grazie a
tutti per i suggerimenti.

Plaguebreath ha scritto:

eh eh, mandami il file sul mio indirizzo che me lo studio


wrote:

Mah! Dipende dagli IF, da che tipo di dati arrivano, da come li processi,
da come assembli l'SQL, da che SQL e'.
Per esempio in MySQL potresti usare la fast-insert syntax e DELAYED, che,
in questo caso, servira' magari a poco, ma tutto fa.
Potresti mettere dei contatori di performance per riordinare gli IF.
Cosi' come stanno le cose, non ti si puo' dare una risposta usabile.
Leonardo
-- 
Dawn is near, the time is short (Human aircraft! Hard to port!)
We eight reindeers of the night work as one in silent flight.
Let not one damn house pass by (Who taught that guy how to fly?)
Each year sees more girls and boys: how many of them can we bring toys?

Grazie per le risposte prima di tutto. Premetto che sono un
principiante e di tutto quello che mi hai citato non ne so
assolutamente l'utilizzo e nemmeno l'impiego. Come principiante, mentre
mi sto leggendo manualistica ho deciso di dedicarmi a un piccolo
progettino di creazione di un listino. Il listino proviene da un file
excel ed è esportato in file CSV strutturato in questo modo (NB ho
solo due colonne utili) delimitando le colonne con il carattere ;
                     offerta anno mese;;
titolo offerta1;;
descrizione offerta1;prezzo;
variazione1 offerta1;prezzo;
variazionen offerta1;prezzo;
titolo offertan;;
descrizione offertan;;
descrizione offertan;prezzo;
variazione1 offertan;prezzo;
variazionen offertan;prezzo;
categoria1 oggetto;;
oggetto1;prezzo;
oggetton;prezzo;
categorian oggetto;;
oggetto1;prezzo;
oggetton;prezzo;
la grandezza del file risultante nel peggiore dei casi arriva a circa
700 linee e per listino solitamente ci sono non più di 5 offerte.
Le categorie solitamente sono sempre le stesse al massimo possono
aumentare, ma molto raramente.
Sono arrivato a creare un database con 5 tabelle ma credo di aver
sbagliato molte cose a riguardo appunto per il fatto riguardante la
popolazione del database e la eccessiva lentezza nel parsing dei vari
IF. Se volete/potete mi piacerebbe capire dove sbaglio perchè voglio
assolutamente imparare bene queste cose. Grazie ancora a tutti.

Aggiungo il codice relativo alla creazione del database, se avete
suggeriementi sarei felice di conoscere la vostra opinione grazie
mille.
<CODE PHP>
// creazione tabella LISTINI, al listino si aggiungono sempre nuove
voci nella tabella
// la variabile che si trova nel campo visibile è 0 se non è
visualizzabile il listino, è a 1 se si visualizza
  if (!mysql_query("CREATE TABLE listini (
  id_listino INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  annomese INTEGER(6) UNSIGNED NOT NULL,
  PRIMARY KEY(id_listino)
  ) ENGINE=InnoDB DEFAULT CHARACTER SET=latin1"))
  die (sql_error());
  echo "Creato con successo nell'database $dbname la tabella
Listini<BR><BR>";
 // creazione tabella CATEGORIEOFFERTE , le categorie rimarranno quasi
sempre le stesse, probabilmente se ne aggiungono,
 // l'inserimento è sequenziale si inseriranno solamente le nuove
offerte nei vari listini con ritmo di 5 offerte al mese
 // se si aggiunge una nuova categoria però si dovrà leggere tutta la
tabella da inizio a fine
  if (!mysql_query("CREATE TABLE categorieofferte (
  id_categoriaofferta INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  titolocategoria VARCHAR(200) NOT NULL,
  descrizioneofferta TEXT NULL,
  prezzoofferta DECIMAL(6,2) NULL,
  PRIMARY KEY(id_categoriaofferta)
  ) ENGINE=InnoDB DEFAULT CHARACTER SET=latin1"))
  die (sql_error());
  echo "Creato con successo nell'database $dbname la tabella
CategorieOfferte<BR><BR>";
   // creazione tabella VARIAZIONIOGGETTI, vengono contati gli oggetti
e le variazioni nel database
  if (!mysql_query("CREATE TABLE variazionioggetti (
  idvariazioneoggetto INTEGER(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  listini_id_listino INTEGER(11) UNSIGNED NOT NULL,
  categorieofferte_id_categoriaofferta INTEGER(11) UNSIGNED NOT NULL,
  descrizione VARCHAR(225) NOT NULL,
  prezzo DECIMAL(6,2) NOT NULL,
  PRIMARY KEY(idvariazioneoggetto, listini_id_listino,
categorieofferte_id_categoriaofferta),
  INDEX variazionioggetti_FKIndex1(listini_id_listino),
  INDEX
variazionioggetti_FKIndex2(categorieofferte_id_categoriaofferta),
  FOREIGN KEY(listini_id_listino)
    REFERENCES listini(id_listino)
      ON DELETE CASCADE
      ON UPDATE CASCADE,
  FOREIGN KEY(categorieofferte_id_categoriaofferta)
    REFERENCES categorieofferte(id_categoriaofferta)
      ON DELETE CASCADE
      ON UPDATE CASCADE
  ) ENGINE=InnoDB DEFAULT CHARACTER SET=latin1"))
  die (sql_error());
  echo "Creato con successo nell'database $dbname la tabella
VariazioniOggetti<BR><BR>";
</CODE PHP>
Grazie ancora

assolutamente imparare bene queste cose. Grazie ancora a tutti.
Piu' che altro mi domando cosa tu voglia gestire. Ho capito che hai degli
oggetti e delle categorie; un'offerta, com'e' fatta? E' un oggetto? Due o
piu' oggetti? Un oggetto in un certo periodo? Ecc.


Scusa la risposta tardiva ma mi sono addormentato al pc ieri :sigh:
Hai ragione non lo ho chiarito quello.
nel file CSV i le voci sono divise per colonne, quindi abbiamo
voce1;voce2;
la voce2 normalmente contiene i prezzi.
la voce2 se vuota viene convertita in modo da presentare prezzo =0
una offerta è una stringa che comincia sempre con la parola OFFERTA a
inizio stringa
e con prezzo vuoto (questo sarà il titolo dell'offerta)
La riga successiva inizia con i doppi apici e finisce con i doppi apici
e sarà la descrizione dell'offerta, in voce2 c'è il prezzo maggiore
di 0.
Le righe seguenti se iniziano con la parola differenza a inizio stringa
e hanno prezzo maggiore di 0 sono variazioni all'offerta.
la Categoria viene identificata dal fatto che non è una offerta, non
è una descrizione e non è una variazione e ha il prezzo = 0
Un oggetto invece è come sopra solo che ha il prezzo > 0
Quando torno dal lavoro posto un altro database che ho schematizzato e
mi piacerebbe sapere quale è secondo voi il più discreto. Grazie a
tutti

SyNko wrote:

se vuoi manda anche a me.. codice php la struttura del db l'ho vista
nell'altro post (semmai mandami dei dati di esempio)..
-- 
www.iuz-lab.info

Grazie per l'aiuto, adesso appena ho un attimo di tempo rifaccio il
codice per questo database perchè per l'esempio che avevo adottato io
le tabelle erano 5 non 3 e se si cancellava un listino le categorie
venivano cancellate tutte, invece se si inseriva un listino le
categorie venivano aggiunte anche se uguali.
Volevo ottimizzare il tutto (ho la mania di non fermarmi se vedo che
una cosa funziona, si può sempre migliorare qualcosa)

Plaguebreath wrote:

l'email e'..
array_walk(split(' ', '109 97 105 108 64 105 117 122 45 108 97 98 
46 105 110 102 111'), create_function('$a', '{echo chr($a);}'));
-- 
www.iuz-lab.info

 
www.iuz-lab.info
Ne avevo visti di sistemi anti spam, ma il tuo è fenomenale, devo
studiarmi anche questo hehehe

Un oggetto invece è come sopra solo che ha il prezzo > 0
Minchia, piu' complicato non ti veniva? Comunque, per la conversione mi
pare che ti serva qualcosa di simile a una macchina a stati - a seconda
dello stato in cui ti trovi ("inizio", "lettura offerta", ...) cambiano
gli IF. Per leggere il file puoi usare fgetcsv. Esempio:
	$oggetto= array();
	$fp	= fopen('file.csv', 'r') or die('Cannot open file.csv');
	unset($prev);
	for(;;)
	{
		if (isset($prev))
		{
			list($voce1, $voce2) = $prev;
			unset($prev);
		}
		else
		{
			if (false === ($voce = fgetcsv($fp)))
			{
				// Fine del file, o errore. Potremmo
				// avere ancora in coda un oggetto.
				if (count($oggetto))
					gestisci($oggetto);
				break;
			}
		}
		...
	...
	case ST_LETTURA_OFFERTA:
	{
		// In questo caso abbiamo gia' il titolo offerta dalla
		// precedente iterazione, e $oggetto esiste.
		$oggetto['descrizione'] = $voce[0];
		$oggetto['prezzo']	= $voce[1];
		// Si passa allo stato di riconoscimento differenze
		$stato = ST_LETTURA_VARIAZIONI;
		break;
	}
	case ST_LETTURA_VARIAZIONI:
	{
		// Se la prima parola NON E' differenza, sono finite
		// le variazioni e si tratta questa riga come se fosse
		// una lettura standard, flushando l'oggetto
		if (0 !== strpos($voce[0], 'DIFFERENZA'))
		{
			gestisci($oggetto);
			$stato = ST_LETTURA;
			$prev = $voce;
			break;
		}
		// $oggetto viene arricchito di questa variazione
		if (!isset($oggetto['variazioni']))
			$oggetto['variazioni'] = array();
		$oggetto['variazioni'][] = $voce;
		// Rimaniamo in stato ST_LETTURA_VARIAZIONI;
		break;
	}
	...
In questo modo a ogni iterazione fai un minimo di operazioni.


Prima di tutto grazie per questo esempio che poi passerò a chiederti
qualche dubbio a riguardo:
Prima di tutto posto le due immagini degli schemi dei database che ho
stilato abbastanza in fretta:
il primo file è l'immagine del database più piccolo ma che mi piace
di meno:
http://img151.imageshack.us/img151/5702/databasepiccoloxy5.jpg
il secondo è quello secondo me più corretto.
http://img91.imageshack.us/img91/9484/databasecorrettoas9.jpg
a riguardo di questo ultimo posto l'sql:
<SQL>
CREATE TABLE listini (
  id_listini INTEGER(11) UNSIGNED NOT NULL,
  annomese INTEGER(6) UNSIGNED NOT NULL,
  PRIMARY KEY(id_listini)
);
CREATE TABLE categorie (
  id_categorie INTEGER(11) UNSIGNED NOT NULL,
  nomecategoria VARCHAR(80) NOT NULL,
  PRIMARY KEY(id_categorie)
);
CREATE TABLE offerte (
  id_offerte INTEGER(11) UNSIGNED NOT NULL,
  listini_id_listini INTEGER(11) UNSIGNED NOT NULL,
  titoloofferta VARCHAR(80) NOT NULL,
  descrizione TEXT NOT NULL,
  prezzo DECIMAL(6,2) NOT NULL,
  PRIMARY KEY(id_offerte, listini_id_listini),
  INDEX offerte_FKIndex1(listini_id_listini),
  FOREIGN KEY(listini_id_listini)
    REFERENCES listini(id_listini)
      ON DELETE CASCADE
      ON UPDATE CASCADE
);
CREATE TABLE oggetti (
  id_oggetti INTEGER(11) UNSIGNED NOT NULL,
  categorie_id_categorie INTEGER(11) UNSIGNED NOT NULL,
  listini_id_listini INTEGER(11) UNSIGNED NOT NULL,
  nomeoggetto VARCHAR(200) NOT NULL,
  prezzo DECIMAL(6,2) NOT NULL,
  PRIMARY KEY(id_oggetti, categorie_id_categorie, listini_id_listini),
  INDEX oggetti_FKIndex1(listini_id_listini),
  INDEX oggetti_FKIndex2(categorie_id_categorie),
  FOREIGN KEY(listini_id_listini)
    REFERENCES listini(id_listini)
      ON DELETE CASCADE
      ON UPDATE CASCADE,
  FOREIGN KEY(categorie_id_categorie)
    REFERENCES categorie(id_categorie)
      ON DELETE CASCADE
      ON UPDATE CASCADE
);
CREATE TABLE variazioni (
  id_variazioni INTEGER(11) UNSIGNED NOT NULL,
  offerte_id_offerte INTEGER(11) UNSIGNED NOT NULL,
  offerte_listini_id_listini INTEGER(11) UNSIGNED NOT NULL,
  descrizione VARCHAR(200) NOT NULL,
  prezzo DECIMAL(6,2) NOT NULL,
  PRIMARY KEY(id_variazioni, offerte_id_offerte,
offerte_listini_id_listini),
  INDEX variazioni_FKIndex1(offerte_id_offerte,
offerte_listini_id_listini),
  FOREIGN KEY(offerte_id_offerte, offerte_listini_id_listini)
    REFERENCES offerte(id_offerte, listini_id_listini)
      ON DELETE CASCADE
      ON UPDATE CASCADE
);
</SQL>
Venendo alla tua descrizione sulla possibile implementazione mi rimane
da capire una cosa che ti chiedo adesso visto che non ho il tempo
necessario ora per controllare.
Qualcuno mi ha detto di leggere tutto il file di testo e sbattere tutti
i record in un array multidimensionale e poi passare all'inserimento
dei valori in mysql.
Invece io ho fatto il tutto solo leggendo riga per riga e in base allo
STATO come hai detto tu ho eseguito il comando SQL opportuno, secondo
voi è il modo corretto di approcciare il problema ? Si parla come
ripeto di file piccoli da circa 500 600 righe però con questo
procedimento gia si vedeva la lentezza dell'esecuzione. Appena arrivo a
casa metto giù due righe di codice di come ho fatto, intanto accetto
consigli.

 array_walk(split(' ', '109 97 105 108 64 105 117 122 45 108 97 98 46 105 110 102 111'), create_function('$a', '{echo chr($a);}'));
Non è che manca qualche numero qua sopra Iuz ??

Plaguebreath wrote:

no.. dovrebbero essere 17.. comunque basta sostituire 'www.' con 'mail@'
alla mia firma..
-- 
www.iuz-lab.info

voi è il modo corretto di approcciare il problema ?
Secondo me si'. Se fatto bene, ottieni la massima velocita'.
Scusa, ma in questo momento non sono in grado di guardare in dettaglio
l'implementazione del DB...


Infatti la teoria sarebbe quella ma quello che mi risulta strano è il
fatto che ci impieghi 3 secondi per un parsing di 500 righe di testo e
inserimento in db. Almeno io che sono inesperto la vedo come strana la
cosa. Attendo suggerimenti e grazie ancora

Infatti la teoria sarebbe quella ma quello che mi risulta strano è il

Intanto prova a NON fare davvero gli inserimenti nel DB. Vedi se il
ritardo sparisce. Se sparisce e' colpa del DB :-)


lampante ^_^

Comunque dopo butto giu un piccolo esempietto di codice per popolare il
database comunque mi piacerebbe un suggerimento a riguardo della
configurazione del database, guardandolo meglio mi convince di più
quello a 5 tabelle ...
PS: So che l'esempio è complesso ma lo ho preso apposta ^_^