Attualmente sono incaricato di implementare uno schema di archiviazione per una quantità relativamente elevata di dati. Ai dati si accederà principalmente per determinare un data point
valore corrente , ma sono anche tenuto a tenere traccia degli ultimi sei mesi di storia per la tendenza / analisi dei dati.
È stato aggiunto un requisito recente per tenere traccia del valore min
/ max
/ sum
per l'ora passata.
NOTA: idealmente, vorrei prendere in considerazione un'opzione MongoDB, ma devo dimostrare di aver esaurito prima le opzioni di SQL Server.
I dati
La tabella seguente rappresenta l'origine dati primaria (interrogata più frequentemente). La tabella avrà circa cinque milioni di righe. Le modifiche ai dati saranno prevalentemente UPDATE
dichiarazioni con dichiarazioni molto occasionali INSERT
dopo il caricamento iniziale dei dati. Ho scelto di raggruppare i dati dataPointId
come sceglierai sempre all values for a given data point
.
// Simplified Table
CREATE TABLE [dbo].[DataPointValue](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[minimum] [decimal](18, 0) NOT NULL,
[hourMinimum] [decimal](18, 0) NOT NULL,
[current] [decimal](18, 0) NOT NULL,
[currentTrend] [decimal](18, 0) NOT NULL,
[hourMaximum] [decimal](18, 0) NOT NULL,
[maximum] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointValue] PRIMARY KEY CLUSTERED ([dataPointId],[valueId])
)
La seconda tabella è notevolmente più grande con circa 3,1 miliardi di righe (che rappresentano gli ultimi sei mesi di dati). I dati di età superiore a sei mesi verranno eliminati; altrimenti INSERT
dichiarazioni di dati rigorosamente (~ 200 righe / sec, 720.000 righe / ora, 17 milioni di righe / settimana).
// Simplified Table
CREATE TABLE [dbo].[DataPointValueHistory](
[dataPointId] [int] NOT NULL,
[valueId] [int] NOT NULL,
[timestamp] [datetime] NOT NULL,
[value] [decimal](18, 0) NOT NULL,
[delta] [decimal](18, 0) NOT NULL
CONSTRAINT [PK_MeterDataPointHistory] PRIMARY KEY CLUSTERED ([dataPointId], [valueId], [timestamp])
)
L'aspettativa è che questa tabella raddoppierà le dimensioni man mano che il numero dei valori dei punti di dati rilevati aumenta a 400 righe / sec (quindi raggiungere ~ 10 miliardi non è fuori questione).
Le domande ( sì, sto chiedendo più di una ... sono strettamente correlate).
Attualmente sto usando un database SQL-Server 2008 R2 Standard Edition. Probabilmente avrò il caso di aggiornare a Enterprise Edition se è possibile ottenere il livello di prestazioni desiderato con le partizioni di tabella (o MongoDB se non è possibile raggiungere i livelli di prestazioni richiesti con SQL-Server). Vorrei il vostro contributo su quanto segue:
1) Dato che ho bisogno di calcolare il min
, max
e sum
per l'ora passata (come in now - 60 minutes
). Qual è l'approccio migliore per tenere traccia dei dati recenti:
Conservare i dati recenti in memoria del servizio dati. Scrivi min / max / media calcolati con ogni AGGIORNAMENTO dei dati.
Eseguire una query sulla cronologia recente dalla tabella della cronologia (influisce sulla domanda successiva?) Durante ogni istruzione UPDATE. Le query accederanno agli ultimi dati per un valore in punti dati e dovrebbero eseguire la scansione solo degli ultimi milioni di record o giù di lì?
Memorizzare la cronologia recente nella riga DataPointValue stessa per evitare la ricerca nella tabella della cronologia? Forse archiviato come stringa delimitata ed elaborato all'interno del proc UPDATE?
Altra opzione che non ho considerato?
2) Per DataPointValueHistory
, le domande sul datable saranno sempre entro dataPointId
e una o più valueId
. I dati richiesti saranno in genere per l'ultimo giorno, settimana o mese, ma in alcuni casi potrebbero essere per i sei mesi interi.
Attualmente sto generando un set di dati di esempio per sperimentare se ha più senso raggruppare in base a dataPointId / valueId / timeStamp o timeStamp / dataPointId / valueId. Se qualcuno ha esperienza con la gestione di un tavolo di queste dimensioni e disposto a offrire la propria intuizione, sarebbe apprezzato. Mi sto appoggiando a quest'ultima opzione per evitare la frammentazione dell'indice, ma le prestazioni della query sono fondamentali.
Cluster
DataPointValueHistory
per dataPointId -> valueId -> timeStampCluster
DataPointValueHistory
per timeStamp -> dataPointId -> valueId
3) Infine, come detto sopra, penso che abbia senso partizionare la DataPointValueHistory
tabella. Qualsiasi suggerimento su come partizionare al meglio i dati della cronologia sarebbe molto apprezzato.
Se prima sono raggruppati per data / ora, sto pensando che i dati dovrebbero essere partizionati per settimana (27 partizioni in totale). La partizione più vecchia verrà eliminata dopo la settimana 27.
Se prima sono raggruppati da dataPointId, sto pensando che i dati dovrebbero essere partizionati da un modulo dell'id?
Dato che ho un'esperienza molto limitata con il partizionamento delle tabelle, la tua esperienza sarebbe apprezzata.