Newsgroup: it.comp.www.php
Titolo: [forse OT] problemi con phpbb e db mysql da 400 mb

Ciao a tutti!
Ho un problema abbastanza serio con phpbb e mysql.
Sono in hosting virtuale, il mio database è diventato sui 420 mb (301842 
messaggi con oltre 6000 utenti)(
www.acquariofilia.biz
), ora il problema 
è che ogni tanto va in palla mysql server (hosting linux) per le troppe 
connessioni (mysql error: too many connections). Spesso si hanno un 
centinaio di utenti online.
Il propietario della ditta di hosting (
sbinternet.it
) si sta 
arrampicando sugli specchi alludento a fantomatici hacker cattivi e 
altre caxxate cercando di darmi la colpa.
Il tizio per cui lavoro però è alquanto arrabbiato per la situazione 
perchè il sito gli va down (con tutto il server di sbinternet) per un 
ora al giorno in intervalli da 20 minuti. E gli sponsor protestano.
Cosa ne pensate? Avete qualche idea sulla causa/risoluzione del problema?
Grazie a tutti cmq!!

 problema?
Connessioni persistenti ed un server dedicato.
-- 
I am what I am, I do what I can
Sei un newbie? Leggi questo 
http://url.repository.biz/go/3C
Vuoi supportarmi? 
http://url.repository.biz/go/3E
Do. Or do not. There is not try.

 Connessioni persistenti ed un server dedicato.
Scusami, mi sono dimenticato di dire che ho già controllato e le 
connessioni persistenti sono disattivate.
Per sicurezza avevo inoltre sostituito ogni mysql_pconnect con 
mysql_connect nel file che gestisce le comunicazioni phpbb/database 
quindi anche se phpbb fosse configurato per farle non potrebbe.
Quindi.. altre idee?

 Quindi.. altre idee?
Utilizzare le connessioni persistenti ed un server dedicato.


Cosa ne pensate? Avete qualche idea sulla causa/risoluzione del problema?
Tanto per cominciare quel che ti ha detto Setec: prova ad usare le
connessioni persistenti. Zero fatica e grossi risultati.
Poi chiedi che sbinternet aumenti il numero di connessioni ammesse
a MySQL da PHP. Fatica minima e buoni risultati (specie se mettono
anche un po' di RAM e una CPU performante sul server MySQL).
Sul medio periodo dovresti cercare di capire da dove arriva quella
marea di connessioni. Qui la fatica aumenta e i risultati non sono
garantiti: come a cercare l'oro, a volte lo trovi, a volte e' solo
pirite :-)
Come primo passo ti servirebbe un sistema per sapere "quali" query
sono fatte piu' spesso e consumano piu' tempo. E quelle si possono
(forse) ottimizzare con indici o riscrivendole.
Se specie le query grosse finiscono prima, il server si trova piu'
leggero e non deve 'ciclare' cosi' tante connessioni simultanee.
Un intervento piu' curato e' quello di vedere se ci sono query che
tirano fuori dati doppi. Per esempio contare delle righe, poi fare
l'elenco e alla fine scrivere quante righe sono. Puoi fare fare il
conto al PHP e risparmiare una COUNT(), che e' economica, pero' un
pochino costa; e "tutto fa", come diceva quello 8-D. Qui devi fare
un po' di interventi di riscrittura del codice.
In altri casi magari puoi eliminare proprio un sacco di query.
Un esempio buttato la':
- Nella home page hai un riquadro news che aggiorni ogni tot. Ora,
non ha senso ricrearlo dal database ogni volta. E potrebbero anche
esserci N altre query molto lunghe altrove che rallentano tutto.
Diciamo che il tuo codice per creare quel riquadro e'
	$query = "SELECT * FROM news...";
	$exec = SQLExec($conn, $query) or die...
 
	while($record = SQLFetchTuple($exec))
	{
		// QUI IL GROSSO DEL CODICE
	}
	SQLFree($exec);
Lo puoi sostituire pari pari con il seguente:
	$query = "SELECT * FROM news...";
	$cache = 'SQLCache.news.1';
	if (!file_exists($cache))
	{
		$exec = SQLExec($conn, $query) or die...
		$blob = array();
		while($record = SQLFetchTuple($exec))
			$blob[] = $record;
		SQLFree($exec);
		$fp = fopen($cache, 'w');
		fwrite($fp, serialize($blob));
		fclose($fp);
	}
	else
		$blob = unserialize(file($cache));
	foreach($blob as $record)
	{
		// QUI IL GROSSO DEL CODICE
	}
Quando fai un aggiornamento a news, cancelli il file SQLCache.news.1, e il
sistema rigenerera' autonomamente tutto quanto.
In teoria nella cache potresti metterci direttamente l'HTML, pero' cosi' i
cambiamenti al codice sono molto ridotti, e addirittura si possono mettere
dentro una funzione (il nome del file di cache puo' essere ricavato ad es.
dall'md5 di $query).
// Prima
	$exec = SQLExec($conn, $query) or die...
	while($record = SQLFetchTuple($exec))
	{
		// QUI IL GROSSO DEL CODICE
	}
	SQLFree($exec);
// Dopo
	$blob = SQLCache($conn, $query) or die...
	foreach($blob as $record)
	{
		// QUI IL GROSSO DEL CODICE
	}
In queste circostanze, se aggiorni le news dieci volta al giorno e hai una
media di cinquemila visitatori al di', il carico, *dovuto a quel riquadro*
sul server MySQL, ti diminuisce di circa il 99.8% :-)
Se quel riquadro (dalle altre prove!) "pesava" per il 10% sul totale, ecco
che hai risparmiato il 99.8% del 10%, cioe' un 9.98%.
Chiaro che se vai a ottimizzare l'angolo in basso a destra della schermata
per i soli utenti uzbeki, alla fine non c'e' gran risparmio :-), pero' con
un po' di pazienza ed oculatezza IN GENERE si possono snellire molto anche
siti grossi, purche' non siano molto "interattivi" (una chat in MySQL, per
esempio, se ne strafrega del trucco della SQL-Cache; mentre gli indici, al
contrario, potrebbero avere una grossa influenza).
Leonardo
-- 
Avere studiato senza mettere in pratica e' inutile;
mettere in pratica senza avere studiato e' pericoloso.
                                                - Conphpucio

 Leonardo
Ho letto solo ora (4/11/2004), Grazie mille per tutte queste 
informazioni. Ho subito applicato i primi due punti e mi sono salvato il 
post per proseguire con calma..
Grazie ancora!!

post per proseguire con calma..
Mi ero dimenticato una precisazione che potrebbe essere molto importante:
: In teoria nella cache potresti metterci direttamente l'HTML, pero' cosi' i
: cambiamenti al codice sono molto ridotti, e addirittura si possono mettere
: dentro una funzione (il nome del file di cache puo' essere ricavato ad es.
: dall'md5 di $query).
:
:// Prima
:	$exec = SQLExec($conn, $query) or die...
:	while($record = SQLFetchTuple($exec))
:	{
:		// QUI IL GROSSO DEL CODICE
:	}
:	SQLFree($exec);
:
:// Dopo
:	$blob = SQLCache($conn, $query) or die...
:	foreach($blob as $record)
:	{
:		// QUI IL GROSSO DEL CODICE
:	}
I due codici sono funzionalmente equivalenti, ma hanno un impatto su PHP e
MySQL che e' molto diverso.
Il primo stressa pochissimo PHP e parecchio MySQL; il secondo non tocca (o
quasi) MySQL, ma utilizza MOLTA RAM per tenere l'array "$blob".
Una query di 7 Mb di risultato per MySQL, nel secondo caso, va a creare un
array potenzialmente di 14-18 Mb, che potrebbe essere piu' di quanto viene
concesso a PHP dal file php.ini; il risultato e' che lo script crasha.
Si puo' ridurre l'impatto usando, nella funzione, non
	$row = mysql_fetch_array($result)
che ritorna roba tipo
	0	=> 'Leonardo Serni'
	'user'	=> 'Leonardo Serni'
	1	=> '5ebe2294ecd0e0f08eab7690d2a6ee69'
	'pass'	=> '5ebe2294ecd0e0f08eab7690d2a6ee69'
	...
ma piuttosto
	$row = mysql_fetch_array($result, MYSQL_ASSOC)
che ritorna
	'user'	=> 'Leonardo Serni'
	'pass'	=> '5ebe2294ecd0e0f08eab7690d2a6ee69'
...cosi' 7 Mb di query ritornano 8-9 Mb di array. Se non basta, sfiga: uno
puo' risparmiare CPU MySQL a spese della memoria, ma risparmiare l'una *E*
l'altra e' rognosa.
===
Detto questo, rimane vero che se io tiro fuori una query da sette mega, le
cose sono due: o mando TUTTI i dati all'utente, e allora il sito e' un po'
pesantuccio se ha pagine da sette mega; oppure no, ed allora forse c'e' il
sistema di non tirare fuori proprio tutti tutti i dati da MySQL.
