Ottimizzazione di uno script: alcune query.

Salve a tutti,

Sto lavorando ad uno script php che dovrà aggiornare un database di prodotti.

Così com'é adesso, a processare un file contenente una serie di prodotti mi impiega circa 37 secondi.

In produzione dovrà processarne intorno al centinaio o anche più, quindi si tratta di un tempo inaccettabile.

Ci sono due task, compiuti da questo file, a cui imputerei lo spreco di tempo.

Si tratta dell'inserimento delle categorie e del collegamento dei prodotti alle categorie.

Mi spiego: la struttura del db è, semplificando, questa:

prodotti(id, dati prodotto...)

categorie(id, nome)

collegamenti(prodotto, categoria)

E' chiaro che ogni prodotto può appartenere a diverse categorie.

Ora, due task vengono effettuati da php con l'ausilio di più query:

- L'inserimento di una categoria nel database: lo script controlla con una SELECT se la categoria esiste già, e se non esiste la crea con una INSERT.

Come posso far si che il controllo sull'esistenza avvenga direttamente nella query di INSERT?

- Il collegamento: per ogni categoria del prodotto viene fatta una SELECT per ottenerne l'ID (ne abbiamo infatti il nome) e una INSERT per inserire il collegamento.

Come posso far si che la INSERT ottenga direttamente da sola l'ID della categoria?

Non ho poi molta dimistichezza con l'SQL diciamo più che basilare.  :-[

Grazie in anticipo ^^

inviato 7 anni fa
sydarex
X 0 X

Di query del tipo di cui parli se ne fanno centinaia in pochissimi secondi. Mi sembra quindi strano che lo script impieghi 37 secondi. Forse dovresti effettuare un profiling dello script per verificare dove realmente sia il problema. Non è che apri e chiudi continuamente la connessione?

Come posso far si che il controllo sull'esistenza avvenga direttamente nella query di INSERT?

potresti effettuare comunque la INSERT ad occhi chiusi e poi ignorare l'eventuale errore per record già esistente. Ovviamente l'errore viene prodotto se stai inserendo un record la cui chiave primaria è già presente nella tabella. Se però la chiave primaria è un ID autoincrement allora il doppione non si creerebbe mai. Per questo motivo dovresti aggiungere alla tabella una ulteriore chiave di tipo UNIQUE sul nome della categoria. In questo modo se tenti di inserire una categoria il cui nome è già presente ricevi un errore.

Oppure potresti lanciare una REPLACE:

http://dev.mysql.com/doc/refman/5.0/en/replace.html

La REPLACE però sostituisce l'eventuale vecchio record con quello nuovo. Anche in questo caso è la chiave primaria o una chiave UNIQUE a determinare se il record esiste già nella tabella, quindi anche questa volta se la chiave primaria è un ID autoincrement dovresti aggiungere una chiave UNIQUE.

Come posso far si che la INSERT ottenga direttamente da sola l'ID della categoria?

La funzione mysql_insert_id() restituisce l'eventuale ID autoincrement generato dall'ultima query lanciata. Ovviamente non è detto che l'INSERT o la REPLACE generino un nuovo ID quindi temo che se il record già esiste tu debba recuperarne l'ID con una SELECT. Comunque dovresti verificare questo comportamento quando lanci una REPLACE e vedere se viene prodotto un nuovo ID in caso di record preesistente. Questo potrebbe essere un problema per i vecchi prodotti collegati a quella categoria che conserverebbero il vecchio ID, a meno di non mettere un ON UPDATE CASCADE su questo campo.

 :bye:

risposto 7 anni fa
Gianni Tomasicchio
X 0 X

Ho provato le seguenti modifiche:

1) Con la chiave UNIQUE alle categorie per evitare la verifica della preesistenza:

Il tempo AUMENTA. Non capisco perché, l'unica idea che mi viene è che la SELECT sia MOLTO più veloce dell'INSERT, e quindi eseguire più SELECT invece che lo stesso numero di INSERT sia più veloce.

Ma quasi 300 secondi sono un numero assurdo. °_°

2) Ottengo un guadagno medio di UN secondo usando una subquery per ottenere l'ID della categoria quando inserisco i collegamenti.

Quindi temo proprio di dover fare il profiling dello script, come hai detto tu.

Come posso fare una cosa del genere, Gianni?

risposto 7 anni fa
sydarex
X 0 X

Il profiling puoi effettuarlo con alcuni ambienti di sviluppo come Zend Studio o PHPEd oppure "a mano" con XDEBUG. Fa una ricerca su Google per avere maggiori informazioni.

 :bye:

risposto 7 anni fa
Gianni Tomasicchio
X 0 X

Grazie dell'aiuto ^^

risposto 7 anni fa
sydarex
X 0 X
Effettua l'accesso o registrati per rispondere a questa domanda