Atualmente, estou encarregado de implementar um esquema de armazenamento para uma quantidade relativamente grande de dados. Os dados serão acessados principalmente para determinar um data point
valor atual , mas também sou obrigado a acompanhar os últimos seis meses do histórico de tendências / análises de dados.
Um requisito recente foi adicionado para rastrear o valor min
/ max
/ sum
da última hora.
NOTA: Idealmente, eu gostaria de considerar uma opção do MongoDB, mas preciso demonstrar que exaurei as opções do SQL-Server primeiro.
Os dados
A tabela a seguir representa a fonte de dados principal (consultada com mais frequência). A tabela terá aproximadamente cinco milhões de linhas. As alterações nos dados serão predominantemente UPDATE
declarações com declarações muito ocasionais INSERT
após o carregamento inicial dos dados. Optei por agrupar os dados, dataPointId
como você sempre estará selecionando 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])
)
A segunda tabela é notavelmente maior, com aproximadamente 3,1 bilhões de linhas (representando os últimos seis meses de dados). Dados com mais de seis meses serão limpos; caso contrário, estritamente INSERT
declarações de dados (~ 200 linhas / s, 720.000 linhas / hora, 17 milhões de linhas / 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])
)
A expectativa é que essa tabela tenha o dobro de tamanho à medida que o número de valores de pontos de dados rastreados aumenta para 400 linhas / s (portanto, atingir ~ 10 bilhões não está fora de questão).
A (s) questão (ões) (sim, estou perguntando mais de uma ... elas estão intimamente relacionadas).
Atualmente, estou usando um banco de dados SQL Server 2008 R2 Standard Edition. Provavelmente, defenderei a atualização para o Enterprise Edition se conseguir o nível de desempenho desejado com partições de tabela (ou o MongoDB se não conseguir atingir os níveis de desempenho necessários com o SQL-Server). Gostaria da sua opinião sobre o seguinte:
1) Dado que preciso para calcular o min
, max
e sum
durante a última hora (como em now - 60 minutes
). Qual é a melhor abordagem para rastrear dados recentes:
Mantenha dados recentes na memória do serviço de dados. Escreva min / max / média calculada com cada atualização de dados.
Consulte o histórico recente da tabela de histórico (afeta a próxima pergunta?) Durante cada instrução UPDATE. A consulta acessaria os dados mais recentes para obter um valor de ponto de dados e só deveria ser digitalizada nos últimos milhões de registros?
Armazenar o histórico recente na própria linha DataPointValue para evitar a pesquisa na tabela de histórico? Talvez armazenado como uma string delimitada e processado dentro do processo UPDATE?
Outra opção que não considerei?
2) Pois DataPointValueHistory
, as consultas contra a tabela de dados sempre serão feitas por dataPointId
e um ou mais valueId
's. Os dados consultados normalmente são do último dia, semana ou mês, mas podem ser dos seis meses completos em alguns casos.
No momento, estou gerando um conjunto de dados de amostra para experimentar se faz mais sentido agrupar por dataPointId / valueId / timeStamp ou timeStamp / dataPointId / valueId. Se alguém tiver experiência em lidar com uma tabela desse tamanho e estiver disposto a oferecer seu insight, isso será apreciado. Estou inclinado para a última opção para evitar a fragmentação do índice, mas o desempenho da consulta é crítico.
Grupo
DataPointValueHistory
por dataPointId -> valueId -> timeStampCluster
DataPointValueHistory
por timeStamp -> dataPointId -> valueId
3) Finalmente, como mencionado acima, acho que fará sentido particionar a DataPointValueHistory
tabela. Todas as sugestões sobre como melhor particionar os dados do histórico serão muito bem-vindas.
Se agrupado primeiro por carimbo de data e hora, acho que os dados devem ser particionados por semana (total de 27 partições). A partição mais antiga seria removida após a semana 27.
Se agrupado primeiro pelo dataPointId, estou pensando que os dados devem ser particionados por algum módulo da identificação?
Como tenho uma experiência muito limitada com o particionamento de tabelas, sua experiência será apreciada.
fonte
Respostas:
Achei essa análise muito útil quando estava pesquisando sobre a construção de uma solução de análise que teria bilhões de linhas em uma tabela.
http://leiliweb.wordpress.com/2012/12/11/partitioned-table-and-index-strategies-using-sql-server-2008/
fonte