Come gestire 3,1 miliardi di righe di dati?


14

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 pointvalore 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/ sumper 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 UPDATEdichiarazioni con dichiarazioni molto occasionali INSERTdopo il caricamento iniziale dei dati. Ho scelto di raggruppare i dati dataPointIdcome 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 INSERTdichiarazioni 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, maxe sumper 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 dataPointIde 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 DataPointValueHistoryper dataPointId -> valueId -> timeStamp

  • Cluster DataPointValueHistoryper timeStamp -> dataPointId -> valueId


3) Infine, come detto sopra, penso che abbia senso partizionare la DataPointValueHistorytabella. 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.


Hai eliminato la versione di questa domanda su StackOverflow?
Taryn

@bluefeet - Sì, è stato contrassegnato come fuori tema ... quindi ho eliminato la domanda SO e ricreata qui (probabilmente avrei dovuto aspettare che fosse migrata).
Calgary Coder,

Nessun problema, mi stavo solo assicurando di non avere domande incrociate.
Taryn

In Standard Edition, è ancora possibile partizionare i dati utilizzando viste partizionate e più tabelle di base. Non sono sicuro se lo hai considerato.
Jon Seigel,

@Jon - Sì, ho preso in considerazione le partizioni manuali delle tabelle (quella scelta particolare si baserà sulla presenza o meno di una licenza Enterprise disponibile ... in caso affermativo, perché il mio ruolo è mio).
Calgary Coder,

Risposte:


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.