sfondo
Ho una rete di circa 2000 sensori, ognuno dei quali ha circa 100 punti dati che raccogliamo a intervalli di 10 minuti. Questi punti dati sono in genere valori int, ma alcuni sono stringhe e float. Questi dati dovrebbero essere conservati per 90 giorni, se possibile di più e ancora efficienti.
Progettazione di database
Inizialmente incaricato di questo progetto, ho scritto un'app C # che scriveva file separati da virgola per ciascun sensore. All'epoca non ce n'erano molti, quando qualcuno voleva guardare le tendenze, aprivamo il CSV in Excel e lo rappresentavamo come necessario.
Le cose sono cresciute e siamo passati a un database MySQL. Ho creato una tabella per ogni sensore (sì, lo so, molte tabelle!); ha funzionato bene, ma ha alcune limitazioni. Con così tante tabelle, è ovviamente impossibile scrivere una query che troverà i dati tra tutti i sensori quando si cerca un valore particolare.
Per la versione successiva, sono passato a Microsoft SQL Server Express e ho inserito tutti i dati dei sensori in una tabella di grandi dimensioni. Anche questo funziona e ci permette di fare query per trovare valori tra tutti i sensori che sono di interesse. Tuttavia, ho incontrato il limite di 10 GB per la versione Express e ho deciso di tornare a MySQL piuttosto che investire in SQL Server Standard.
La domanda
Sono soddisfatto delle prestazioni e della scalabilità di MySQL, ma non sono sicuro che sia meglio attenersi all'approccio basato su tutti i dati in una tabella. 10 GB in un unico tavolo sembrano richiedere un design diverso. Dovrei menzionare che la necessità di eseguire query sui dati per la rappresentazione grafica è ancora presente e sono preoccupato che ci saranno problemi di prestazioni per una query che rappresenta, ad esempio, i dati di temperatura per un sensore per tutti i 90 giorni. (In altre parole, il grafico dovrebbe essere qualcosa che è veloce da produrre, senza aspettare che SQL ordini attraverso pile di dati solo per isolare il sensore di interesse.)
Devo dividere questa tabella in qualche modo per aumentare le prestazioni? O non è insolito avere un tavolo così grande?
Ho indici sulle colonne Sensor ID e Timestamp, che sono praticamente i limiti che definiscono qualsiasi query. (ovvero ottenere i dati per il sensore X da tempo A a tempo B).
Ho letto un po 'di sharding e partizionamento, ma non penso che siano appropriati in questo caso.
Modificare:
Sulla base di commenti e risposte finora, alcune informazioni aggiuntive potrebbero essere utili:
Memoria non indefinita: attualmente non conservo i dati negli ultimi 90 giorni. Ogni giorno, eseguo una query che rimuove i dati più vecchi di 90 giorni. Se in futuro diventerà importante, ne conserverò di più, ma per ora è sufficiente. Questo aiuta a mantenere le dimensioni sotto controllo e le prestazioni elevate (er).
Tipo di motore: l'implementazione originale di MySQL utilizzava MyISAM. Questa volta, durante la creazione delle tabelle per la nuova implementazione (una tabella di dati anziché molte), sono state impostate automaticamente InnoDB. Non credo di avere un requisito per l'uno o l'altro.
Normalizzazione: ci sono ovviamente altre tabelle oltre alla tabella di raccolta dati. Queste tabelle di supporto memorizzano cose come le informazioni di rete per i sensori, le informazioni di accesso per gli utenti, ecc. Non c'è molto da normalizzare (per quanto ne so). La ragione per cui la tabella di dati ha così tante colonne è che ci sono tante variabili per ogni sensore. (Temperature multiple, livelli di luce, pressione dell'aria, ecc.) La normalizzazione per me significa che non ci sono dati ridondanti o gruppi ripetuti. (Almeno per 1NF.) Per un dato sensore, la memorizzazione di tutti i valori in un determinato momento richiede una riga di dati e non vi sono relazioni 1: N coinvolte lì (che vedo).
Potrei dividere la tabella funzionalmente, creando (per esempio) tutti i valori relativi alla temperatura in una tabella e tutti i valori relativi alla pressione dell'aria in un'altra. Anche se questo potrebbe migliorare l'efficienza per chi effettua una query solo sulla temperatura, devo comunque inserire tutti i dati contemporaneamente. Tuttavia, il guadagno di efficienza potrebbe essere utile per le operazioni SELECT. Ovviamente, sarebbe meglio separare la tabella verticalmente in base alla frequenza con cui gli utenti richiedono i dati. Forse è tutto ciò che dovrei fare. Suppongo che nel porre la mia domanda cerco conferma che valga la pena farlo.
Modifica 2:
Utilizzo dei dati: in definitiva gran parte dei dati non viene mai esaminata o necessaria, poiché in genere ci concentriamo solo su elementi con problemi. Ma nel tentativo di trovare problemi utilizziamo vari strumenti per cercare i dati e determinare su quali elementi ingrandire.
Ad esempio, abbiamo notato una correlazione tra un valore di utilizzo della memoria (un programma software proprietario specifico del cliente) e un riavvio / arresto anomalo. Uno dei punti dati che raccolgo si riferisce a questo utilizzo della memoria e sono stato in grado di esaminare i dati storici per mostrare che i dispositivi diventano instabili dopo il superamento di un determinato utilizzo della memoria. Oggi, per il sottoinsieme di dispositivi che eseguono questo software, controllo questo valore ed emetto un comando di riavvio se è troppo alto. Fino a quando questo non è stato scoperto, non pensavo che la raccolta di questi dati fosse utile.
Per questo motivo, ho sostenuto che i circa 100 punti dati siano raccolti e archiviati, anche se il valore è discutibile. Ma nel normale uso quotidiano, gli utenti in genere esaminano forse una dozzina di questi parametri. Se un utente si interessa a una particolare area geografica, può (utilizzando il software) generare grafici o fogli di calcolo di dati per forse alcune decine di sensori. Non è raro guardare un grafico di 30 giorni con due o tre linee della trama che mostrano cose come temperatura, pressione dell'aria e livelli di luce. In questo modo verrebbe eseguita una query simile alla seguente:
SELECT sensor_id, location, data_timestamp, temp1, air1, light1
FROM data
WHERE data_timestamp >= '2012-02-01'
AND sensor_id IN (1, 2, 3);
(Nella versione originale di MySQL, in cui ogni sensore aveva la propria tabella, sarebbero state emesse tre query separate, ma i risultati combinati nel software per creare il grafico.)
Poiché la data
tabella contiene tante righe (~ 10 milioni), nonostante gli indici siano attivi id
e data_timestamp
, le prestazioni sono notevolmente peggiori dello scenario a più tabelle (4500 righe restituite in 9 secondi anziché meno di un secondo con questo esempio). La capacità di trovare quali sensori soddisfano determinati criteri è praticamente zero nello schema a più tabelle, e quindi il motivo per passare a una singola tabella.
Questo tipo di query può essere eseguito da più utenti in rapida successione mentre selezionano diversi gruppi di dati e confrontano i grafici di ciascun risultato. Può essere abbastanza frustrante attendere quasi 10 secondi per grafico o foglio di calcolo.
I dati vengono eliminati dopo 90 giorni. Potrebbe essere archiviato ma attualmente non è un requisito.
Speriamo che queste informazioni aiutino a mostrare più adeguatamente come i dati vengono utilizzati dopo la raccolta e l'archiviazione.