fundo
Eu tenho uma rede de aproximadamente 2000 sensores, cada um com cerca de 100 pontos de dados que coletamos em intervalos de 10 minutos. Esses pontos de dados geralmente são valores int, mas alguns são strings e floats. Esses dados devem ser armazenados por 90 dias, mais se possível e ainda eficientes.
Design do Banco de Dados
Quando originalmente encarregado desse projeto, escrevi um aplicativo C # que escrevia arquivos separados por vírgula para cada sensor. Na época, não havia tantos, quando alguém queria examinar as tendências, abriríamos o csv no Excel e o representaríamos como necessário.
As coisas cresceram e mudamos para um banco de dados MySQL. Criei uma tabela para cada sensor (sim, eu sei, muitas tabelas!); tem funcionado bem, mas tem algumas limitações. Com tantas tabelas, é obviamente impossível escrever uma consulta que encontre dados entre todos os sensores ao procurar um valor específico.
Para a próxima versão, mudei para o Microsoft SQL Server Express e coloquei todos os dados do sensor em uma tabela grande. Isso também funciona e nos permite fazer consultas para encontrar valores entre todos os sensores de seu interesse. No entanto, cheguei ao limite de 10 GB para a versão Express e decidi voltar ao MySQL em vez de investir no SQL Server Standard.
A questão
Estou feliz com o desempenho e a escalabilidade do MySQL, mas não tenho certeza se é melhor seguir a abordagem de todos os dados em uma tabela. 10 GB em uma única tabela parece estar pedindo um design diferente. Devo mencionar que a necessidade de consultar dados para gráficos ainda está lá, e estou preocupado que haja problemas de desempenho em uma consulta que represente graficamente, por exemplo, dados de temperatura para um sensor nos 90 dias completos. (Em outras palavras, o gráfico deve ser rápido para produzir, sem esperar que o SQL classifique pilhas de dados apenas para isolar o sensor de interesse.)
Devo dividir esta tabela de alguma forma para aumentar o desempenho? Ou não é incomum ter uma mesa tão grande?
Eu tenho índices nas colunas Sensor ID e Timestamp, que são praticamente os limites que definem qualquer consulta. (ou seja, obtenha dados para o sensor X do tempo A ao tempo B).
Eu li um pouco sobre sharding e particionamento, mas não acho que sejam apropriados nesse caso.
Editar:
Com base nos comentários e respostas até agora, algumas informações adicionais podem ser úteis:
Armazenamento não indefinido: atualmente não armazeno dados nos últimos 90 dias. Diariamente, eu executo uma consulta que remove dados com mais de 90 dias. Se isso se tornar importante no futuro, armazenarei mais, mas por enquanto é suficiente. Isso ajuda a manter o tamanho sob controle e o desempenho alto (er).
Tipo de mecanismo: A implementação original do MySQL usou o MyISAM. Ao criar as tabelas dessa vez para a nova implementação (uma tabela de dados em vez de muitas), elas padronizaram o InnoDB. Não acredito que tenha um requisito para um ou outro.
Normalização: Naturalmente, existem outras tabelas além da tabela de coleta de dados. Essas tabelas de suporte armazenam itens como informações de rede para os sensores, informações de login para usuários etc. Não há muito o que normalizar (tanto quanto eu sei). A razão pela qual a tabela de dados tem tantas colunas é que existem muitas variáveis de cada sensor. (Múltiplas temperaturas, níveis de luz, pressão do ar etc.) Normalização para mim significa que não há dados redundantes ou grupos repetidos. (Pelo menos para 1NF.) Para um determinado sensor, o armazenamento de todos os valores em um determinado momento requer uma linha de dados e não há relacionamentos 1: N envolvidos (o que vejo).
Eu poderia separar a tabela funcionalmente, criando (por exemplo) todos os valores relacionados à temperatura em uma tabela e todos os valores relacionados à pressão do ar em outra. Embora isso possa melhorar a eficiência de quem faz uma consulta apenas de temperatura, ainda preciso inserir todos os dados de uma só vez. Ainda assim, o ganho de eficiência pode valer a pena para operações SELECT. Obviamente, seria melhor dividir a tabela verticalmente com base na frequência com que os usuários solicitam os dados. Talvez seja tudo o que devo fazer. Suponho que, ao fazer minha pergunta, busco confirmação de que fazer isso valerá a pena.
Edição 2:
Uso de dados: em última análise, muitos dos dados nunca são analisados ou necessários, porque geralmente focamos apenas nos itens com problemas. Mas, ao tentar encontrar problemas, usamos várias ferramentas para pesquisar os dados e determinar em quais itens ampliar.
Por exemplo, notamos uma correlação entre um valor de uso de memória (um programa de software proprietário específico do cliente) e uma reinicialização / falha. Um dos pontos de dados que eu coleciono refere-se a esse uso de memória e pude examinar os dados históricos para mostrar que os dispositivos se tornam instáveis depois que um determinado uso de memória é excedido. Hoje, para o subconjunto de dispositivos que executam este software, verifico esse valor e emito um comando de reinicialização se estiver muito alto. Até que isso fosse descoberto, eu não achava que a coleta desses dados tivesse valor.
Por esse motivo, afirmei que os cerca de 100 pontos de dados são coletados e armazenados, mesmo que o valor seja questionável. Mas no uso diário normal, os usuários normalmente examinam talvez uma dúzia desses parâmetros. Se um usuário se interessar por uma área geográfica específica, ele pode (usando software) gerar gráficos ou planilhas de dados para talvez algumas dezenas de sensores. Não é incomum olhar para um gráfico de 30 dias com duas ou três linhas de plotagem mostrando coisas como temperatura, pressão do ar e níveis de luz. Fazer isso executaria uma consulta semelhante a esta:
SELECT sensor_id, location, data_timestamp, temp1, air1, light1
FROM data
WHERE data_timestamp >= '2012-02-01'
AND sensor_id IN (1, 2, 3);
(Na versão original do MySQL, onde cada sensor tinha sua própria tabela, três consultas separadas seriam emitidas, mas os resultados combinados em software para criar o gráfico.)
Como a data
tabela contém muitas linhas (~ 10 milhões), apesar de ter índices ativados id
e data_timestamp
, o desempenho é notavelmente pior que o cenário de várias tabelas (4500 linhas retornadas em 9 segundos, em oposição a menos de um segundo neste exemplo). A capacidade de descobrir quais sensores atendem a certos critérios é praticamente zero no esquema de várias tabelas e, portanto, o motivo para mudar para uma única tabela.
Esse tipo de consulta pode ser feito por vários usuários em rápida sucessão, pois eles selecionam diferentes grupos de dados e comparam os gráficos de cada resultado. Pode ser bastante frustrante aguardar quase 10 segundos por gráfico ou planilha.
Os dados são descartados após 90 dias. Pode ser arquivado, mas atualmente não é um requisito.
Esperamos que essas informações ajudem a mostrar mais adequadamente como os dados são usados após a coleta e o armazenamento.