Questo post è rivolto ai guru del forum in ambito database
Avendo a che fare con una montagna di dati volevo proporre un sistema di caching query alternativo.
Tutto quello che si trova in rete, inerente il PHP, si basa su questi passaggi
- fai la SELECT
- butta tutto in un array
- serializza l'array
- salvalo in un file
Andando a curiosare nel mondo Oracle ho scoperto che in realtà qusti furboni hanno procedure interne che si occupano di gestire updates o altro ma di fatto seguono lo stesso iter, quindi anche qui niente ...
Quello che mi fa imbestialire è che questo sistema non considera l'esecuzione di query potenzialmente lente, dove per lente si intendono secondi.
In questo sistema io vedo delle problematiche insormontabili. Faccio un esempio:
La tabella è stata modificata, parte il circo cominciando dalla select.
In primo luogo se non blocco in toto la tabella il circo può partire per ogni utente che in quell'istante va a chiedere l'informazione ... e va beh, risolvibile ...
In secondo luogo mi ritrovo un risultato totale parsato in un array.
Per ovvi motivi non posso usare questo metodo per centinaia di migliaia di informazioni, per il semplice fatto che invece di aiutare il server lo andrei ad impegnare 5 volte di più per prima eseguire la slow query, poi fetchare tutto in un array che sta in RAM, poi serializzare il mastodontico array considerando che serialize è una funzione molto lenta ... in fine mi creo un file con tutto serializzato il che comporta che ogni volta devo:
- leggermi un intero file in RAM
- deserializzare il contenuto
- usarlo così com'è salvo ulteriore parsing tramite PHP che tutti sappiamo non essere famoso per le prestazioni
Su un sito hanno comparato le varie performances e sembra che anche APC sia troppo lento rispetto il solo array in RAM, ma sommando lettura file più deserializzazione forse APC è l'unica alternativa rapida.
Quello che non mi piace di questo sistema è che non permette, se vogliamo salvaguardare RAM e stress del server e di PHP, di salvare appunto centinaia di migliaia di records.
A questo punto si è costretti a dover usare l'intero circo per ogni query, dove nella query è compresa la clausola LIMIT, GROUP BY, ORDER BY eccetera eccetera.
Come tutti sappiamo, quando si ha una lista di informazioni è naturale poter scegliere l'ordine, il raggruppamento, o in fine la paginazione.
Questo sistema richiede N query salvate, con tutte le procedure già descritte in salvataggio e recupero dati, per ogni singola pagina più ogni singolo GROUP BY ed ogni singolo ORDER BY.
ABOMINIO !!!
La mia proposta si basa su cache nello stesso database ... qual'è il senso?
E' vero che il caching di dati, soprattutto per query statiche, è probabilmente il modo più veloce, ma nessuno ha pensato questo:
- questo sistema è davvero scalabile?
- per ogni condizione, quante query in più sono costretto a fare?
- se una query è lenta, perchè devo ripeterla stressando tutti per ogni pagina da N risultati mostrati?
Dalle mie ricerche pare che nessun prof abbia scritto una soluzione, sembra quasi stiano tutti li a creare guestbooks ... invece eccovi l'idea, ed ecco perchè vorrei le vostre opinioni in merito:
- creo una tabella dedicata al caching di quella SELECT
- la SELECT è opzionalmente libera da clausole, il che significa che prendo tutti i risultati con clausole, per le statiche, e tutti senza clausole, per le NON statiche
- siccome la clausola LIMIT non implica minor tempo di esecuzione query, casomai limita quello di fetching rows, anche questa diventa opzionale ... ergo prendo tutti i risultati
- l'operazione è fatta internamente in modo da evitare stress al server, alla RAM, al PHP, e delegare il tutto al DB, che non dovrà fare altro che schiaffare il risultato direttamente in tabella
- a questo punto ho una tabella con tutti i risultati della SELECT, capace di darmi diversi GROUP BY, ORDER BY, LIMIT, senza alcuno stress di qualsivoglia JOIN o altro
Per il solo LIMIT l'esecuzione è di 0.003 secondi a prescindere dalla pagina, il tutto considerando che la tabellla è stata creata una sola volta con una query di questo tipo:
codice:
CREATE TABLE cache.tmp_{$sha1Query} {$Query}
dove $Query è l'intera query SELECT QUELLO CHE VUOI senza LIMIT o calusole opzionali, e sha1 è l'hash scelto per rendere univoca la query correndo meno rischio di collisioni.
A questo punto ho una tabella con i risultati già estrapolati dove per prenderli non dovrò fare altro che un
codice:
SELECT * FROM cache.tmp_{$sha1Query}
aggiungendo eventualmente
oppure
codice:
GROUP BY field_name LIMIT 0, 50
oppure altro ancora ... lavorando sempre sullo stesso result set di risultati.
I risultati sono impressionanti, ho azzerato le JOIN se non in creazione cache, ho risultati manipolabili a mio piacere su una lista di risultati pre elaborata, ho una tabella invece di una stringa serializzata, dove poter lavorare comodamente come meglio credo per mostrare qualunque tipo di combinazione invece di creare N combinazioni quante sono le clausole della giornata.
I tempi di creazione tabella sono dal 10 al 30% maggiori della sola query, ovvero facendo tutto tramite PHP spenderei circa il 300% del tempo invece di lavorare nel core del DB.
Alterando o meno le tabelle con una index UNSIGNED INT(10) AUTO_INCREMENT non ho notato troppi benefici, ma per scrupolo l'ho fatto comunque.
A tutto questo va aggiunto che qualunque cosa succeda, non ho problemni col PHP perchè ammesso saltasse l'interprete, finisse il timeout, altro ancora, il database multi thread continuerebbe a finire il suo comodo lavoro, il quale è ovviamente flaggato su una tabella muletto che si occupa di evitare concorrenza e problemi di altro tipo.
Ora, la domanda che vorrei farvi è la seguente:
cosa ne pensate di questo metodo, considerando che il problema principale non è quante volte mi connetto al DB o quante query faccio, bensì quanto voglio guadagnare per ottenere risultati variabili mille mila volte per ogni sezione del portale?
Grazie a chi saprà darmi consigli, insulti, risposte