Opportunità di riprogettazione del database: quale progetto di tabella utilizzare per questa raccolta di dati del sensore?


13

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 datatabella contiene tante righe (~ 10 milioni), nonostante gli indici siano attivi ide 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.


Affinché questa domanda ottenga la risposta giusta , probabilmente dovresti espandere il modo in cui i dati vengono effettivamente utilizzati. Sei davanti alla curva sulla profondità delle informazioni che hai fornito finora ma potresti porre la tua domanda da un'angolazione sbagliata.
Mark Storey-Smith,

Buon punto, @Mark, approfondirò anche questo. Stavo cercando di non avere una domanda troppo lunga per paura che potesse sopraffare.
JYelton,

Risposte:


5

Dovresti pensare di partizionare la tabella per un grande motivo.

Tutti gli indici presenti su una tabella gigante, anche solo un indice, possono generare molto carico della CPU e I / O del disco solo per eseguire la manutenzione dell'indice durante l'esecuzione di INSERT, UPDATE e DELETE.

Ho scritto un post precedente il 7 ottobre 2011 sul perché il partizionamento delle tabelle sarebbe stato di grande aiuto. Ecco un estratto dal mio post precedente:

Il partizionamento dei dati dovrebbe servire a raggruppare i dati che sono logicamente e coerentemente nella stessa classe. Le prestazioni di ricerca in ciascuna partizione non devono essere la considerazione principale finché i dati sono raggruppati correttamente. Una volta ottenuto il partizionamento logico, concentrati sul tempo di ricerca. Se si stanno solo separando i dati solo per ID, è possibile che non sia mai possibile accedere a molte righe di dati per letture o scritture. Ora, questa dovrebbe essere una considerazione importante: individuare tutti gli ID a cui si accede più frequentemente e partizionarli. Tutti gli ID con accesso meno frequente dovrebbero risiedere in una grande tabella di archivio che è ancora accessibile dalla ricerca dell'indice per quella query "una volta in una luna blu".

Puoi leggere il mio intero post in seguito.

Per andare subito al sodo, devi cercare e scoprire quali dati vengono usati raramente nella tabella da 10 GB. Tali dati dovrebbero essere collocati in una tabella di archivio facilmente accessibile nel caso in cui siano necessarie query ad hoc per natura storica. La migrazione di tale archivio da 10 GB, seguita dalla OPTIMIZE TABLEtabella da 10 GB, può comportare un Working Set che è più veloce per eseguire SELECT, INSERT, UPDATE e DELETE. Anche DDL andrebbe più veloce su un set di lavoro da 2 GB rispetto a un tavolo da 10 GB.

AGGIORNAMENTO 2012-02-24 16:19 EDT

Due punti da considerare

  1. Dal tuo commento, sembra che la normalizzazione sia ciò di cui potresti aver bisogno.
  2. Potrebbe essere necessario eseguire la migrazione di tutto ciò che risale a più di 90 giorni in una tabella di archivio, ma allo stesso tempo accedere all'archivio e al set di lavoro contemporaneamente. Se i tuoi dati sono tutti MyISAM, ti consiglio di utilizzare il motore di archiviazione MERGE. Innanzitutto, creare la mappa della tabella MERGE una volta che unisce una tabella MyISAM del set di lavoro e una tabella MyISAM di archivio. Conserveresti i dati per meno di 91 giorni in una tabella MyISAM e trasferiresti nell'archivio tutti i dati più vecchi di 90 giorni. Si interrogherà solo la mappa della tabella MERGE.

Ecco due post che ho scritto su come usarlo:

Ecco un post aggiuntivo che ho scritto su tabelle con molte colonne

Troppe colonne in MySQL


Ci sono colonne che sono meno frequentemente necessarie, ma tutti i sensori ricevono circa la stessa percentuale di attenzione. Quindi, posso immaginare che dividere la tabella verticalmente sarebbe vantaggioso. Ad esempio, una tabella a 20 colonne (a cui si accede frequentemente) e una tabella a 80 colonne (a cui si accede raramente). Non sono sicuro che sia la stessa cosa del partizionamento.
JYelton,

Grazie per la modifica. Ho letto il tuo post su "Troppe colonne in MySQL". Modificherò la mia domanda con alcuni punti aggiuntivi che potrebbero essere utili.
JYelton,

5

Interessante ... Se tutti i sensori producono lo stesso tipo di dati, ha senso metterli tutti nella stessa tabella, ma con quella quantità di dati, posso capire perché dovresti preoccuparti delle prestazioni.

90 giorni sono i soliti tempi per i quali produci un grafico? In tal caso, potresti avere due tabelle: la tabella dei dati del sensore principale che memorizza i dati da 90 (o un po 'di più se vuoi un po' di gioco) giorni fa fino ad oggi e tutto ciò che è più vecchio di quello va nella tabella di archivio. Ciò potrebbe aiutare a ridurre le dimensioni della tabella da cui vengono generati i rapporti e, si spera, la maggior parte dei 10 GB di dati sarà nella tabella di archivio e non nella tabella principale. Il lavoro di archiviazione può essere programmato per essere eseguito di notte.

Forse prendere in considerazione anche la creazione di un database di report separato che memorizza i dati in una struttura che è migliore per la generazione di report da (tabelle progettate per corrispondere più da vicino a ciò che si sta interrogando, e forse pre-calcolare e aggregare valori che altrimenti richiederebbero molto tempo generare, se possibile) e ripopolarlo dal database principale su base regolare (ad esempio ogni notte). Naturalmente, se hai bisogno dei report generati da dati aggiornati, questo potrebbe non funzionare così bene.


Conservare qualsiasi cosa negli ultimi 90 giorni a questo punto non è necessario ma sarebbe bello. Sono d'accordo che sia meglio archiviare in una tabella "archivio". I grafici e l'analisi dei dati vanno da poche ore a tutti i 90 giorni. La maggior parte delle richieste grafiche utilizza solo la settimana scorsa di dati, ma i grafici a 90 giorni sono comuni. La nostra azienda non ha (ancora) richiesto rapporti più lunghi.
JYelton,

@JYelton: in questo approccio potresti avere tutti i livelli che desideri. La tabella più recente potrebbe avere solo da Oggi. Il prossimo tavolo potrebbe avere da oggi a 2 settimane fa. La tabella successiva potrebbe avere da Oggi a 90 giorni fa. L'ultimo tavolo potrebbe TUTTO.
FrustratedWithFormsDesigner,

Se ti capisco correttamente, stai dicendo di replicare la tabella, ma con coperture di periodi di tempo diversi. Quindi, se qualcuno richiede un rapporto di 7 giorni, verrebbe utilizzata una tabella che risale a solo una settimana. Se poi si espandessero a 8 giorni, verrebbe utilizzata la tabella successiva più grande (ad es. 30 giorni)? Ciò migliorerebbe sicuramente la velocità delle query di breve durata, ma a un costo di archiviazione (economico) e logica di programmazione per gestire le tabelle a più livelli (non altrettanto economico).
JYelton,

@JYelton: Sì, penso che tu lo capisca correttamente. Se gli intervalli del periodo di tempo della query sono standard (oggi - 1 giorno, oggi - 7 giorni, oggi - 30 giorni, oggi - 90 giorni), non penso che sarà troppo difficile poiché saprai sempre quale tabella colpire. Se gli intervalli di tempo potrebbero essere di lunghezza variabile in cui l'inizio dell'intervallo potrebbe non essere la data corrente, allora si è corretti che la logica da implementare diventerà complicata e le query che attraversano le tabelle potrebbero essere costose con le operazioni UNION su più tabelle.
FrustratedWithFormsDesigner,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.