Pagina 1 di 3 1 2 3 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 30
  1. #1

    [MySQL] esperti - caching senza serializzazione

    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
    1. fai la SELECT
    2. butta tutto in un array
    3. serializza l'array
    4. 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:
    1. leggermi un intero file in RAM
    2. deserializzare il contenuto
    3. 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:
    1. creo una tabella dedicata al caching di quella SELECT
    2. 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
    3. 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
    4. 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
    5. 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
    codice:
    LIMIT 50, 50
    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
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  2. #2
    Utente di HTML.it L'avatar di luca200
    Registrato dal
    Apr 2002
    Messaggi
    4,120
    Ho l'impressione che mi sia sfuggito qualcosa, perché la prima domanda che mi viene è di una banalità sconcertante:

    come la mettiamo con gli update alla tabella?


    P.S. non giurerei che la LIMIT senza order by non abbrevi l'esecuzione della query

  3. #3
    ma tu vuoi fare questo sistema di cache-query per quale motivo?

    mi spiego meglio, le query che devi fare tu, servono alla fine per generare una pagina HTML come per tutti i siti di informazione che prendono i contenuti dal DB, oppure servono per altro ( del tipo statische e cose del genere ) ?

  4. #4
    Originariamente inviato da luca200
    Ho l'impressione che mi sia sfuggito qualcosa, perché la prima domanda che mi viene è di una banalità sconcertante:

    come la mettiamo con gli update alla tabella?
    in questo caso la scelta è di gestire l'aggiornamento tramite cronjob o webcron. Diciamo che ogni ora possiamo eliminare le tabelle al fine di far rigenerare la cache.

    Un pò come per i servizi bancari, dove non c'è real-time ma updates periodici ... del resto ora stiamo usando un lifetime come ogni sistema di cache che non si basa sul last update delle tabelle (queste sono continuamente aggiornate in back end durante tutto il giorno e tutta la notte)


    Originariamente inviato da luca200
    P.S. non giurerei che la LIMIT senza order by non abbrevi l'esecuzione della query
    la query è composta da due parti, esecuzione e fetching. A prescindere da ORDER BY o GROUP BY i tempi di esecuzione con o senza LIMIT sono identici, mentre quelli di fetching, a seconda dei CONCAT o delle formattazioni, variano ... ed ovviamente variano anche a seconda del numero di righe ottenute.

    Senza GROUP BY e o ORDER BY una query con LIMIT è veloce e se non hai alcuna JOIN, filtro, altro, formattazioni comprese, rasenta tempi di esecuzione vicini allo zero.

    Te lo posso giurare
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  5. #5
    Originariamente inviato da xnavigator
    ma tu vuoi fare questo sistema di cache-query per quale motivo?

    mi spiego meglio, le query che devi fare tu, servono alla fine per generare una pagina HTML come per tutti i siti di informazione che prendono i contenuti dal DB, oppure servono per altro ( del tipo statische e cose del genere ) ?
    Le query servono per generare pagine HTML, ovvio ... considera che i siti di informazione salvano prima news o altro e decidono poi quando mostrarle durante il giorno. Non è che appena inseriscono nel DB queste vengono pubblicate.

    Per alcune sezioni del portale basate nello specifico su un Advanced Search, non è possibile basarsi sugli aggiornamenti delle tabelle e calcolare runtime i risultati. Di qui la proposta alternativa che permette di lavorare meglio e runtime con ricerche più frequenti.

    Tutte le altre tabelle potrebbero anche basarsi sul last update, insomma a me sembra più flessibile dell'altro sistema ed i risultati ottenuti sono eccellenti ... ma appunto volevo i vostri pareri e le vostre domande, visto mai sia sfuggito qualcosa a me
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  6. #6
    Finalmente qualcuno che parla di caching!!!
    Guarda io è un bel po' che ormai ho smesso di mischiare query, codice php (e non) etc.
    Io faccio una cache di tutto, ovviamente non su array ma oggetti.
    In base a quello, ho ottenuto risultati sorprendenti anche memorizzando migliaia e migliaia di dati in pochi secondi. Alla fine io cerco di creare un equilibrio tra informazioni che mi servono subito, e informazioni che mi servono poi. In base a quello faccio caricamenti parziali, e arricchisco la cache appena mi serve altro.
    Le tabelle le memorizzo senza where, group by, o limit (anche perchè il limit nei db in cui lavoro io, purtroppo non esiste!).
    Però tramite oggetti poi è una cavolata ordinare come voglio io, filtrare come voglio io, etc etc.
    E per le relazioni con le tabelle...le carico solo quando serve.
    In genere il mio strato di software che collega il mio Data access layer e il mio entity layer, che chiamo repository, lo strutturo caricando in cache pezzi di dati, e arricchendolo con metodi che mi linkano le tabelle relazionate, che in genere lancio solo quando mi serve.

    Comunque l'argomento mi interessa molto, sviluppiamolo e magari mettiamo sul piatto un po' di esempi pratici in cui ci siamo trovati ad applicare queste strategie, vi va?

  7. #7
    Originariamente inviato da andr3a
    Le query servono per generare pagine HTML, ovvio ... considera che i siti di informazione salvano prima news o altro e decidono poi quando mostrarle durante il giorno. Non è che appena inseriscono nel DB queste vengono pubblicate.
    Allora guarda ti dico come faccio io, sistema che a me ha salvato la vita. ( Ma penso che ci hai pensato già. )

    Io il sistema di cache lo faccio a monte, alla pagina HTML. E cioè: ho fatto in modo che la pagina che mostrasse gli articoli del sito fosse 'statica' nel senso che quella è e quella rimane, non ci sono parti "HTML" che necessariamente si aggiornano come potrebbe essere una colonna 'Ultimi aritcoli pubblicati' o cose del genere. Una volta pubblicato un articolo la pagina HTML che lo contiene quella è e quella rimane. ( Ovviamente per generare quest'articolo vengono fatte una decina di query che tanto semplici non sono e che se venissero fatte per ogni utente andrebbe a pu**ane tutto )

    Cosi la prima volta che l'articolo deve essere generato, cioè la prima visita che un utente porta a quell'articolo necessariamente devono essere eseguite le varie query per costrutire la pagina HTML, ma una volta fatto veiene preso il contenuto tramite ob_* e messo in un file, che può essere: cache/md5($_SERVER['REQUEST_URI']).bk

    la pagina dell'articolo ogni volta controlla se è presente un file .bk nella cartella cache ovviametne controllando l'url richiesto con md5, se è presente viene preso il contenuto, viene stampato ( che in questo caso corrisponde all'output generato dalla prima visita ) e viene interrotto lo script cosi da non fare nessuna query.

    --
    Se nel caso la pagina dell'articolo dovesse cambiare basta cancellare il file di cache in modo che venga rigenerato aggiornato automaticamente, se ti serve posto il mio codice

  8. #8
    *** www.php.net/APC

    http://it2.php.net/manual/it/function.apc-store.php
    http://it2.php.net/manual/it/function.apc-fetch.php
    http://it2.php.net/manual/it/function.apc-delete.php
    e molte altre ancora

    *** http://eaccelerator.net/
    http://bart.eaccelerator.net/doc/php...ccelerator_get
    http://bart.eaccelerator.net/doc/php...ccelerator_put
    http://bart.eaccelerator.net/doc/php...accelerator_rm
    http://bart.eaccelerator.net/doc/php...tor_cache_page
    e molte altre ancora

    *** http://xcache.lighttpd.net/
    http://xcache.lighttpd.net/wiki/XcacheApi

    tutta la doc sta li

    *** http://it.php.net/memcache

    mi stuffa postare i link, stanno li

    *** http://sharedance.pureftpd.org/project/sharedance

    Senza considerare che poi c'è PEAR che contiene un package per far questo tipo di lavori che supporta questi vari sistemi
    http://pear.php.net/package/System_SharedMemory/

    ------

    si, lo so, non c'entra molto con mysql, però considera vari fattori, tra cui il primo è che tu hai fatto questa proposta perché parli direttamente di salvare le query e lavorare li su, ma questa necessità non la hai più se esegui un caching parziale delle pagine

    Io faccio qualcosa di simile rispetto a xnavigator, ovvero se ho la pagina html composta da N blocchi e output di N moduli salvo SINGOLARMENTE ognuno di questi e costruisco la pagina: questo è necessario perché se ci stanno dei dati variabili, come il numero di utenti connessi, chi fa il compleanno, gli utenti presenti in una sezione e cosi via tante altre situazioni che varia, posso limitarmi ad aggiornare, se ne ha necessità, una sola componente o non cacharla proprio se gli aggiornamenti sono continui e rendono inutile la cache

    Questo sistema poggiato a uno delle strutture di sopra (escluso il pear perché il codice me l'ho sono scritto per i fatti miei) è probabilmente più performante anche se singolarmente più lento ... voglio dire che probabilmente l'operazione di caching della pagina HTML è lenta rispetto al salvataggio della query PERO' facendo una cache della singola query devi in ogni caso ricostruire l'intera pagina html con il risultato che anche se il caching è più veloce php deve comunque fare un papocchio di lavoro (poi tutto dipende effettivamente da come il codice è scritto, da come lavora e da che rigiri fa)

    Inoltre se non si utilizza l'hash per creare i nomi di queste cache parziali ma si usa, in chiaro, l'url, più i valori in get più i valori in post più altri valori tuoi (o se hai problemi di lunghezza delle chiavi prendi e te le inserisci in una chiave l'elenco e l'hash del file a cui si riferiscono) hai la possibilità che da panello di controllo, quando devi fare un update a un contenuto puoi effettuare una ricerca su questo alberò in base a dei valori che dici tu e cancellare la cache in blocco facendola rigenerare al volo al codice al primo accesso

    è un sistema, ovviamente, completamente diverso, però il risultato finale va considerato nell'insieme

    nota: a tutti i sistemi elencati di sopra puoi sempre aggiungere delle tabelle di cache su tipo HEAP/MEMORY su mysql

    #####
    edit
    #####

    altra cosa che potrebbe interessare
    http://mysql-udf-global-user-variabl...user-variables

  9. #9
    io i problemi li ho con mysql, non con il mero risultato finale ... e mi piacerebbe cachare risultati parziali, avendo controllo "in the middle", invece di avere risultati gia' pronti pe rquella singola casistica immutabile al cambio di esigenze, group by o altro.

    In pratica il tuo sistema, xnavigator, ha gli stessi limiti della serializzazione rows ... mentre le mie wesigenze e quello che ho gia' creato e proposto e' piu' vicino a quello che fa m.figus

    danie', grazie per le info, leggero' con cura il tutto ma APC per ora non e' presente e il discorso di non voler avere tutto statico, a livello di risutlato, rimane
    Formaldehyde a new Ajax PHP Zero Config Error Debugger

    WebReflection @WebReflection

  10. #10
    guarda io è un po' di tempo che non lavoro con mysql, l'ho sempre usato per roba piccolina e anche all'università mi è sempre stato detto che le prestazioni ottime si hanno o su oracle, o se si va su microsoft, con sql server.
    Io per esigenze lavorative mi trovo a lavorare molto col secondo ultimamente, e devo dire che i risultati sono molto buoni. Di query bene o male ne faccio un paio...prima mi carico tutte le tabelle, poi mi scrivo le associazioni, poi se devo aggiornare mi aggiorno prima il db e poi di nuovo la cache. Oppure a volte è utile aggiornare solo la cache, e toccare il db solo dopo altre procedure...insomma credo di avere un controllo maggiore, e soprattutto prestazioni maggiori!
    Considera che spesso ho necessità di lavorare con db esterni e perciò quelle percentuali che tu hai riportato sui tempi di accesso, in questi casi salgono esponenzialmente!

    In ogni caso se devo fare un'analisi delle casistiche, devo dire che utilizzare una cache è assolutamente utile per scrivere meglio un programma, ma può essere inutile con tabelle che hanno qualche migliaio di dati (a livello di prestazioni).
    Quando si inizia a lavorare con db di centinaia di tabelle, e alcune con centinaia di migliaia o addirittura milioni di records, la cache è assolutamente fondamentale..

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.