fdalesio, Tiago, gik25, luckylinux, probid, gorka, mix
Query eseguite all'arrivo di un utente
Tabella con Query divise per table e INSERT/SELECT
Tool per l'importazione da PHPStats
Query Inserimento e aggregazione dei dati
http://www.gt-stats.org/gtstats-core/
Programmazione strutturata in classi
Classe QueryWriter (nessuna query dovrà essere eseguita senza usare questa classe)
Con altri sistemi di statistiche tramite XML (importazione da script a xml e da xml a GTStats)
Il codice di GTStats sarà inizialmente PHP 4, strutturato in numerose classi e funzioni. Cercando di ridurre al minimo la replicazione del codice. Il codice sarà documentato. Cercheremo di sfruttare PEAR, template engine e la massima ottimizzazione possibile per un Database.
Il codice MySQL delle query sarà gestito esclusivamente all'interno della classe QueryWriter, questa classe conterrà internamente una matrice nella quale ogni cella rappresenta una query SQL. Tramite i metodi pubblici di questa classe saranno passati i parametri e le informazioni necessarie incapsulate a loro volta in un oggetto.
In pratica quando devo fare una query passo a una funzione la tabella su cui voglio operare, e la modalità (INSERT, SELECT, ecc) e i parametri. Il codice MySQL è contenuto dentro questa classe che va studiata a tavolino.
Risparmiare spazio su DB è molto importante: l'ip deve diventare un numero (si usa la funzione ip2long di PHP), dobbiamo sfruttare i tipi enum e le funzioni hash to integer come CRC32 MD5 e in generale altre Hash a 32 bit
Partiamo da considerazioni su un sistema esistente, al fine di capire come migliorarlo. PHPStats è un ottimo software, ma ha dei problemi di efficienza dovuti al numero di operazioni di scrittura su database per ciascun utente.
In questo file word troverete il codice PHP che descrive le operazioni di query che PHPStats fa ad ogni accesso.
Query.doc Query tracking utente
Documentazione tabelle PHPStats
Tabella dettagli su PHPStats
visitor_id | ip | host | agent | lang | date | referer | currentPage | reso | colo | titlePage |
varchar(50) | varchar(15) | varchar(50) | varchar(255) | varchar(10) | int(10) | varchar(255) | varchar(255) | varchar(10) | varchar(10) | varchar(255) |
E' un id casuale di questo tipo: 9noYQgY7Ji8UkV07Sijn7GWRtKvEZy sono 30 caratteri cioè più di 931.322.574.615.478.515.625.000.000.000.000.000.00 0.000.000.000.000 utenti monitorabili. Un po' troppi, no?
Questo campo è salvato come VARCHAR(50). Per un campo fisso a 30 caratteri sarebbe meglio un CHAR(30). Ancora meglio tuttavia è sostituire tale id con un intero. Basta un bigint.
In effetti, anche un errore su un milione sarebbe più che accettabile, usare un unsigned a 32 bit (2^32 = 4 miliardi) potrebbe andare più che bene, ma si deve tenere conto di un fattore statistico noto come paradosso del giorno del compleanno. Ovvero non interessa la probabilità che un utente coincida con l'altro, ma quella che un qualsiasi utente coincida con qualsiasi altro.
In effetti quasi tutto in PHPStats è salvato come varchar, mentre il suo uso dovrebbe essere ridotto al minimo. CHAR ad esempio è preferivile se la dimensione è fissa, ma valori come l'ip possono essere salvati come numeri.
Gli user agent sono standard vanno sostituiti con un intero hard coded, se la ricerca non lo trova scrive in un file hash(id) = "$useragent". Hash perchè così ogni sistema PHPStats userà gli stessi id per i nuovi useragent.
Risoluzione deve essere un int, la conversione deve essere fatta tramite array associativo hard coded.
Colori tyniint unsigned di 4 invece che varchar(10).
"http://www." sarà sostituito con un carattere singolo magari non url safe (che quindi non potrà mai comparire in un url) accorciando referer e current page.
Il dominio sarà salvato come int e sarà hard coded in un file scritto da PHP stesso.
Lang occupa poco, comunque si potrebbe metterlo sempre come int.
Utilizzare tutto hard coded serve a ridurre al minimo il numero di query al DB.
PHPStats salva la configurazione su db. Quindi una prima query mysql serve solo a leggere la configurazione. Un include da file è in linea teorica molto più veloce visto che i db hanno requisiti di sicurezza e atomicità che li rendono più lenti. Senza considerare il caching del file in ram e il ritardo dovuto al trasferimento in rete se il DB è presente su un altro server.
PHPStats salva nella tabella referer il mese come stringa.
Un numero di 10 cifre salvato come stringa occupa 10 byte, salvato come int ne occupa 2 o 4 a seconda della precisione.
PHPStats non usa indici. In effetti effettua quasi solo inserimenti. Bisogna verificare con test se si tratta di una scelta ottimale.
Bisogna testare INSERT contro INSERT DELAYED e decidere quando passare da uno all'altro.
è un must. La velocità di una query in scrittura MySQL dipende anche dalle dimensioni, e lo spazio su database offerto dai vari hoster è spesso limitato.
Come viene salvato il title della pagina nella tabella pages? Si può passare il parametro tramite js?
http://www.maani.us/charts/index.php?menu=Gallery&submenu=3D_Pie
PHP stats fa dei controlli prima di ogni scrittura, del tipo: se le righe sono 1000 cancellane una. Lo svuotamento se frequente dovrebbe essere fatto con truncate. L'ottimizzazione va fatta di notte, e solo se ci sono cancellazioni, altrimenti è inutile.
In pratica per fare una query ne va ad eseguire cinque.
Controllare il funzionamento dei simil cronjob casuali, ogni tot utente uno scatena il controllo o meglio ogni utente ha la probabilità 1/tot di scatenare il controllo.