2009-02-08 8 views
5

Voglio iniziare a contare il numero di volte in cui una pagina web viene visualizzata e quindi è necessario un qualche tipo di contatore semplice. Qual è il miglior metodo scalabile per fare ciò?Qual è il modo migliore per implementare un campo contatore in MySQL

Supponiamo che ho una tabella Frobs dove ogni riga corrisponde a una pagina - alcune opzioni evidenti sono:

  1. Avere un unsigned int NumViews campo nella tabella Frobs che ottiene aggiornati su ogni vista utilizzando UPDATE Frobs SET NumViews = NumViews + 1 . Semplice ma non così bravo nel ridimensionamento come ho capito.

  2. Avere una tabella separata FrobViews dove viene inserita una nuova riga per ogni vista. Per visualizzare il numero di visualizzazioni , è quindi necessario eseguire un semplice SELECT COUNT(*) AS NumViews FROM FrobViews WHERE FrobId = '%d' GROUP BY FrobId. Ciò non comporta alcun aggiornamento, quindi è possibile evitare il blocco della tabella nelle tabelle MyISAM; tuttavia, le prestazioni di lettura ne risentiranno se si desidera visualizzare il numero di visualizzazioni su ciascuna pagina.

Come si fa?

C'è qualche buon consiglio qui: http://www.mysqlperformanceblog.com/2007/07/01/implementing-efficient-counters-with-mysql/ ma mi piacerebbe sentire le opinioni della comunità SO.

Attualmente sto utilizzando InnoDb, ma sono interessato alle risposte sia per InnoDb che per MyISAM.

risposta

2

Vorrei prendere il secondo approccio e aggregare i dati nella tabella dalla prima soluzione su base regolare. In questo modo ottieni i vantaggi di entrambe le soluzioni. Per essere più chiari: Ad ogni colpo inserisci una riga in una tabella (consenti di chiamarla hit_counters). Questa tabella ha solo un campo (il pageid). Ogni x secondi si esegue uno script (tramite un cronjob) che aggrega i dati della tabella hit_counters e li inserisce in una seconda tabella (denominandola "hits".) Sono disponibili due campi: il pageid e gli hit totali

non sono sicuro, ma imho non si InnoDB aiuta molto per soluzione 1 se si ottiene molti successi nella stessa pagina: InnoDB blocca la fila durante l'aggiornamento in modo che tutti gli altri aggiornamenti per questa riga sarà ritardata

in base. il programma scritto in te potrebbe anche raggruppare insieme gli aggiornamenti contando nella tua applicazione e aggiornando il database solo ogni x secondi. Funzionerebbe solo se usi un linguaggio di programmazione in cui hai memoria persistente (come Java Servlet ma non PHP)

3

Se la scalabilità è più importante della precisione assoluta delle cifre, è possibile memorizzare il conteggio delle visualizzazioni nell'applicazione per un breve periodo piuttosto che colpire il database in ogni visualizzazione di pagina, ad esempio aggiornare il database solo una volta ogni 100 visualizzazioni .

Se l'applicazione si arresta in modo anomalo tra gli aggiornamenti del database, ovviamente si perderanno alcuni dei dati, ma se si riesce a tollerare una certa quantità di imprecisione, questo potrebbe essere un approccio utile.

0

Quello che faccio, e potrebbe non applicarsi allo scenario, è nella stored procedure che prepara/restituisce i dati che vengono visualizzati sulla pagina, faccio il contatore del contatore di aggiornamento allo stesso tempo restituisce i dati - in questo modo, c'è una sola chiamata al server che riceve entrambi i dati e aggiorna il contatore nella stessa chiamata.

Se non si utilizza SP, (o se non ci sono dati di database sulla pagina) questa opzione potrebbe non essere disponibile per voi, ma se lo siete, è qualcosa da considerare.

3

L'inserimento in un database non è qualcosa che si desidera fare sulle visualizzazioni di pagina. È probabile che si verifichino dei problemi con l'aggiornamento dei database slave con tutti gli inserti poiché la replica è single threaded su MySQL.

Nella mia azienda serviamo 25 milioni di pagine al giorno e abbiamo adottato un approccio a più livelli.

Il contatore di viste è memorizzato in una tabella separata con 2 colonne (profileId, viewCounter) entrambi sono interi senza segno.

Per gli articoli visualizzati di rado si aggiorna la tabella sulla vista pagina. Per gli articoli visti di frequente aggiorniamo MySQL circa 1/10 del tempo. Per entrambi i tipi aggiorniamo Memcache su ogni hit.
int Memcache::increment (string $key [, int $value = 1 ])

if (pageViews < 10000) { UPDATE page_view SET viewCounter=viewCounter+1 WHERE profileId = :? }

else if ((int)rand(10) == 1) { //UPDATE page_view SET viewCounter= ?:cache_value WHERE profileId = :? }

fare count (*) è molto inefficiente a InnoDB (MyISAM mantiene contare statistiche nell'indice), ma MyISAM sarà bloccare la tabella sulla legge ridurre la concorrenza. fare un conteggio() per 50.000 o 100.000 righe richiederà molto tempo. Fare una selezione su un PK sarà molto veloce.

Se è necessaria una maggiore scalabilità, è possibile dare un'occhiata a redis

Problemi correlati