Newsgroup: it.comp.www.php
Titolo: congestione mysql

Ciao, vorrei sottoporvi un problema che ho avuto con un applicativo in
php-mysql per un call center con circa 40 operatrici.
Ho una tabella con 50000 nominativi. L' operatrice accede al primo
nominativo disponibile che blocco immediatamente per impedirne l'uso alle
altre operatrici. Tutto sembrava funzionare bene ma dopo un po ci siamo
trovati nella situazione in cui più operatrici accedevano allo stesso
nominativo. Come si può spiegare una cosa del genere? Forse mysql non è
all'altezza di un compito simile e devo usare un altro tipo di db oppure ho
trascurato io qualcosa in php?
Il procedimento che uso è questo:
1- mysql_query("select *  from nominativi where bloc='NO'");
2- con mysql_fetch_array prendo il primo nominativo disponibile
3- blocco il record del nominativo appena raccolto
Grazie mille!

 Grazie mille!
mi sembra normale che si causino blocchi, anzi considerando che i 
risultati delle query sono sempre gli stessi e prendi sempre il 1° 
record mi sembra normale che quando 2 operatrici chiamino quasi in 
contemporanea risulti lo stesso nominativo.
Devi considerare che le operazioni da te citate possono essere esequite 
in "parallelo" quindi devi avvalerti di tecniche di programmazione 
concorrente.
Es.
Supponi 2 operatrici A e B.
Supponi che le operazioni di A e B si "intreccino" in questo modo:
A esegue l'operazione 1
B esegue l'operazione 1
A esegue 2 e 3
B esegue 2 e 3
Ovviamente sia ad A che a B risulterà lo stesso nominativo.
Puoi metterci una "pezza" mettendo un ordinamento "random" alla query 
per la ricerca del nominativo il che RIDUCE gli errori, non li elimina.
Per eliminarli devi utilizzare i lock sugli item (la tabella dei 
nominativi) che mysql dovrebbe disporre solo dalla versione 4 in su se 
non vado errato.
ciao
Alesi_27



Prova:
1. mysql_query("LOCK TABLE nominativi WRITE;");
2. select ID from nominativi ... LIMIT 1
3. bloc=SI where id=ID
4. mysql_query("UNLOCK TABLE nominativi;");
5. mysql_query("SELECT * FROM nominativi WHERE id=ID;");
 
6. mysql_query("LOCK TABLE nominativi WRITE;");
7. bloc=NO where id=ID
8. mysql_query("UNLOCK TABLE nominativi;");
Le operazioni 1-4 e 6-8 le puoi mettere in due funzioni GetAndLockRecord()
ed UnlockRecord().
Oppure puoi usare le funzioni GET_LOCK, IS_FREE_LOCK e RELEASE_LOCK sempre
nelle funzioni GetAndLockRecord() e UnlockRecord().
Infine, puoi usare le transazioni (MySQL recente, tabelle InnoDB/BDB)
Leonardo
-- 
Time's angles, mages tell, conceal a place
incredible, beyond the mundane mind;
night-shrouded and between the seas of space
dread creatures drift in the ageless winds.


Sicuramente le query vengono eseguite quasi in contemporanea da più
operatrici ma le istruzioni dovrebbero impiegare pochi millesimi di secondo
tra la selezione del record e il blocco del record no? Se anche uso i lock
di mysql sono comunque istruzioni che impiegano del tempo (parliamo sempre
di inezie..) e a rigor di logica non potrebbero risolvere il problema.
Sicuramente l'accesso random è una buona idea ma mi chiedo sempre dove sta
il punto debole. Non esiste proprio un'istruzione php-mysql più snella che
trovi più rapidamente il primo record disponibile? Dopo tutto 40 operatrici
non mi sembrano un' enormità..
Ringrazio entrambi per l'aiuto!

 10 minuti stampati.
No i nominativi non vengono stampati, vengono usati uno per volta in questo
modo:.
$query=mysql_query("SELECT * FROM clienti WHERE chiamato='N'") or
die(mysql_error());
$id=mysql_fetch_object($query);
$id_cliente=$id->id_cliente;
mysql_query("UPDATE clienti SET chiamato='Y' WHERE
id_cliente='$id_cliente'")or die(mysql_error());
Io continuo ad avere dubbi sulla velocità di mysql..
Grazie!

 Io continuo ad avere dubbi sulla velocità di mysql..
Mi sembra un problema di concorrenza... ecco alcuni dritte:
la select si va a cercare tutti (!!!) i clienti non ancora contattati, tu
prendi il primo libero e lo segni come controllato.
immagina che due operatrici lancino quasi contemporaneamente lo script: nel
tempo che viene fatta la select entrambe avranno gli stessi risultati,
quindi andranno a recuperare lo stesso id ed entrambe lo segneranno come
contattato.
Tanto per cominciare è inutile leggere ogni volta 50000 record, non ti pare?
Limita la SELECT ad un risultato
$query=mysql_query("SELECT * FROM clienti WHERE chiamato='N' LIMIT 1")
e sarà così MOLTO più veloce. Indicizza le tabelle con "id_cliente" e
"contattato".
Quando lo devi contrassegnare, controlla che non sia già stato fatto (sembra
ridondante, ma come hai visto non lo è)
mysql_query("UPDATE clienti SET chiamato='Y' WHERE id_cliente='$id_cliente'
AND chiamato='N' ")or die(mysql_error());
Ora che hai fatto la query puoi vedere quante righe sono state modificate
(mysql_affected_rows): se sono 0 il cliente era già stato preso, quindi te
ne devi cercare un altro.
Spero risolva il tuo problema!
Ludovico Grossi

 non mi sembrano un' enormità..
Ti rimando al post con la mia soluzione.
Ludovico Grossi

 Ringrazio entrambi per l'aiuto!
ciao
Alesi_27