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 point
valor 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
/ sum
de 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 UPDATE
declaraciones con declaraciones muy ocasionales INSERT
después de la carga de datos inicial. He optado por agrupar los datos dataPointId
ya 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 INSERT
declaraciones 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
, max
y sum
para 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 dataPointId
uno 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
DataPointValueHistory
por dataPointId -> valueId -> timeStampCluster
DataPointValueHistory
by timeStamp -> dataPointId -> valueId
3) Finalmente, como se mencionó anteriormente, creo que tendrá sentido dividir la DataPointValueHistory
tabla. 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.