¿Cómo gestionar 3.1 billones de filas de datos?

14

Actualmente tengo la tarea de implementar un esquema de almacenamiento para una cantidad relativamente grande de datos. Se accederá principalmente a los datos para determinar un data pointvalor actual , pero también se me exige que haga un seguimiento de los últimos seis meses del historial de tendencias / análisis de datos.

Se agregó un requisito reciente para rastrear el valor min/ max/ sumde la última hora.

NOTA: Idealmente, me gustaría considerar una opción MongoDB, pero necesito demostrar que he agotado las opciones de SQL Server primero.

Los datos

La siguiente tabla representa la fuente de datos primaria (consulta más frecuente). La tabla tendrá aproximadamente cinco millones de filas. Los cambios de datos serán predominantemente UPDATEdeclaraciones con declaraciones muy ocasionales INSERTdespués de la carga de datos inicial. He optado por agrupar los datos dataPointIdya que siempre estará seleccionando 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 segunda tabla es notablemente más grande con aproximadamente 3,1 mil millones de filas (que representan los últimos seis meses de datos). Los datos de más de seis meses serán eliminados; de lo contrario, estrictamente INSERTdeclaraciones de datos (~ 200 filas / seg, 720,000 filas / hora, 17 millones de filas / semana).

// 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])

)

La expectativa es que esta tabla duplicará su tamaño a medida que el número de valores de puntos de datos rastreados aumente a 400 filas / seg (por lo que alcanzar ~ 10 mil millones no está fuera de discusión).

La (s) pregunta (s) (sí, pido más de una ... están estrechamente relacionadas).

Actualmente estoy usando una base de datos SQL-Server 2008 R2 Standard Edition. Probablemente voy a defender la actualización a Enterprise Edition si puedo obtener el nivel de rendimiento deseado con particiones de tabla (o MongoDB si no puede alcanzar los niveles de rendimiento requeridos con SQL-Server). Me gustaría su opinión sobre lo siguiente:


1) Dado que necesito calcular el min, maxy sumpara la última hora (como en now - 60 minutes). ¿Cuál es el mejor enfoque para rastrear datos recientes?

  • Retener datos recientes en la memoria del servicio de datos. Escriba el mínimo / máximo / promedio calculado con cada ACTUALIZACIÓN de datos.

  • Consulte el historial reciente de la tabla de historial (¿impacta la siguiente pregunta?) Durante cada declaración de ACTUALIZACIÓN. ¿Consulta accedería a los últimos datos para obtener un valor de punto de datos y solo debería escanear los últimos millones de registros más o menos?

  • ¿Almacenar el historial reciente en la fila DataPointValue para evitar la búsqueda en la tabla del historial? ¿Quizás almacenado como una cadena delimitada y procesada dentro del proceso UPDATE?

  • ¿Otra opción que no he considerado?


2) Para DataPointValueHistory, las consultas contra el datable siempre serán por dataPointIduno y más valueId. Los datos consultados generalmente serán del último día, semana o mes, pero en algunos casos pueden ser durante los seis meses completos.

Actualmente estoy generando un conjunto de datos de muestra para experimentar si tiene más sentido agrupar por dataPointId / valueId / timeStamp o timeStamp / dataPointId / valueId. Si alguien tiene experiencia en el manejo de una mesa de este tamaño y está dispuesto a ofrecer su opinión, se lo agradeceríamos. Me estoy inclinando hacia la última opción para evitar la fragmentación del índice, pero el rendimiento de la consulta es crítico.

  • Clúster DataPointValueHistorypor dataPointId -> valueId -> timeStamp

  • Cluster DataPointValueHistoryby timeStamp -> dataPointId -> valueId


3) Finalmente, como se mencionó anteriormente, creo que tendrá sentido dividir la DataPointValueHistorytabla. Cualquier sugerencia sobre cómo particionar mejor los datos del historial sería muy apreciada.

  • Si se agrupa primero por la marca de tiempo, creo que los datos deberían dividirse por semana (27 particiones en total). La partición más antigua se purgaría después de la semana 27.

  • Si agrupada por dataPointId primero, ¿estoy pensando que los datos deberían ser particionados por algún módulo de la identificación?

Como tengo una experiencia muy limitada con el particionamiento de tablas, agradeceríamos su experiencia.

Codificador de Calgary
fuente
¿Eliminó la versión de esta pregunta en StackOverflow?
Taryn
@bluefeet: Sí, se marcó como fuera de tema ... así que eliminé la pregunta SO y la volví a crear aquí (probablemente debería haber esperado a que se migrara).
Calgary Coder
No hay problema, solo me estaba asegurando de que no tuviéramos una pregunta cruzada.
Taryn
En la Edición estándar, aún puede particionar los datos utilizando vistas particionadas y múltiples tablas base. No estoy seguro si lo consideraste.
Jon Seigel
@ Jon: Sí, he considerado las particiones de tabla manuales (esa elección en particular se basará en si hay una licencia Enterprise disponible o no ... en caso afirmativo, ¿por qué elegir la mía?).
Calgary Coder

Respuestas: