Oportunidade de redesenho do banco de dados: Qual design de tabela usar para essa coleta de dados do sensor?

13

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 datatabela contém muitas linhas (~ 10 milhões), apesar de ter índices ativados ide 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.

JYelton
fonte
Para que esta pergunta obtenha a resposta certa , você provavelmente deve expandir como os dados são realmente usados. Você está à frente da curva na profundidade das informações que você forneceu até agora, mas pode estar fazendo a sua pergunta pelo ângulo errado.
Mark-Storey-Smith
Bom ponto, @ Mark, também vou elaborar isso. Eu estava tentando não ter uma pergunta muito longa por medo de que ela fosse esmagadora.
JYelton

Respostas:

5

Você deve pensar em particionar a tabela por um grande motivo.

Todos os índices que você possui em uma tabela gigante, mesmo que apenas um índice, podem gerar muita carga de CPU e E / S de disco apenas para executar a manutenção do índice ao executar INSERTs, UPDATEs e DELETEs.

Escrevi uma postagem anterior em 7 de outubro de 2011 sobre o motivo pelo qual o Particionamento de Tabela seria uma grande ajuda. Aqui está um trecho do meu post passado:

O particionamento de dados deve servir para agrupar dados que são lógica e coesa na mesma classe. O desempenho da pesquisa em cada partição não precisa ser a principal consideração, desde que os dados sejam agrupados corretamente. Depois de obter o particionamento lógico, concentre-se no tempo de pesquisa. Se você estiver apenas separando dados apenas por ID, é possível que muitas linhas de dados nunca sejam acessadas para leituras ou gravações. Agora, isso deve ser uma consideração importante: localize todos os IDs acessados ​​com mais frequência e particione com isso. Todos os IDs acessados ​​com menos frequência devem residir em uma grande tabela de arquivamento que ainda está acessível pela pesquisa de índice para a consulta "uma vez na lua azul".

Você pode ler meu post inteiro mais tarde.

Para ir direto ao ponto, você precisa pesquisar e descobrir quais dados raramente são usados ​​na sua tabela de 10 GB. Esses dados devem ser colocados em uma tabela de arquivamento que seja facilmente acessível, caso você precise de consultas adhoc de natureza histórica. A migração desse arquivamento dos 10 GB, seguida pela OPTIMIZE TABLEtabela de 10 GB, pode resultar em um Conjunto de Trabalho mais rápido para executar SELECTs, INSERTs, UPDATEs e DELETEs. Até o DDL seria mais rápido em um conjunto de trabalho de 2 GB do que em uma tabela de 10 GB.

UPDATE 2012-02-24 16:19 EDT

Dois pontos a considerar

  1. Pelo seu comentário, parece que a normalização é o que você pode precisar.
  2. Pode ser necessário migrar tudo com mais de 90 dias para uma tabela de arquivamento, mas ainda acessar o conjunto de arquivamento e trabalho ao mesmo tempo. Se seus dados são todos MyISAM, eu recomendo usar o mecanismo de armazenamento MERGE. Primeiro, você cria o mapa da tabela MERGE uma vez que une uma tabela MyISAM do conjunto de trabalho e uma tabela MyISAM de arquivo morto. Você manteria os dados com menos de 91 dias em uma tabela MyISAM e faria o rollover de todos os dados com mais de 90 dias no arquivo morto. Você consultaria apenas o mapa da tabela MERGE.

Aqui estão dois posts que eu fiz sobre como usá-lo:

Aqui está um post adicional que fiz em tabelas com muitas colunas

Muitas colunas no MySQL

RolandoMySQLDBA
fonte
Existem colunas menos necessárias, mas todos os sensores recebem aproximadamente a mesma porcentagem de atenção. Assim, posso imaginar que dividir a tabela verticalmente seria vantajoso. Por exemplo, uma tabela de 20 colunas (acessada com frequência) e uma tabela de 80 colunas (acessada com pouca frequência). Não tenho certeza se isso é a mesma coisa que particionamento.
JYelton
Obrigado pela edição. Eu li o seu post sobre "Muitas colunas no MySQL". Vou editar minha pergunta com alguns pontos adicionais que podem ser úteis.
JYelton
5

Interessante ... Se todos os sensores produzem o mesmo tipo de dados, faz sentido colocá-los todos na mesma tabela, mas com essa quantidade de dados, posso ver por que você estaria preocupado com o desempenho.

90 dias são a quantidade habitual de tempo para a qual você produz um gráfico? Nesse caso, você pode ter duas tabelas: a tabela principal de dados do sensor que armazena dados de 90 (ou um pouco mais, se você quiser uma folga) dias atrás até hoje e tudo mais antigo que isso está na tabela de arquivamento. Isso pode ajudar a reduzir o tamanho da tabela da qual os relatórios são gerados, e esperamos que a maioria dos seus 10 GB de dados esteja na tabela de arquivamento, e não na tabela principal. O trabalho de arquivamento pode ser agendado para execução noturna.

Talvez também considere a criação de um banco de dados de relatório separado que armazene os dados em uma estrutura melhor para gerar relatórios (tabelas projetadas para corresponder melhor ao que você está consultando e talvez pré-calcular e agregar valores que, de outra forma, levariam muito tempo para serem gerados). gerar, se possível) e preenchê-lo novamente do banco de dados principal regularmente (como noturno). Obviamente, se você precisar dos relatórios gerados a partir de dados atualizados, isso pode não funcionar tão bem.

FrustratedWithFormsDesigner
fonte
Armazenar qualquer coisa nos últimos 90 dias nesse momento não é necessário, mas seria bom. Concordo que é melhor armazenar em uma tabela de "arquivo morto". Os gráficos e a análise de dados variam de meras horas a 90 dias completos. A maioria das solicitações gráficas utiliza apenas os dados da semana passada, mas gráficos de 90 dias são comuns. Nossa empresa ainda não solicitou relatórios mais longos.
JYelton
@JYelton: Você pode ter quantas camadas desejar nessa abordagem. A tabela mais atual poderia ter somente hoje. A tabela a seguir pode ter hoje a 2 semanas atrás. A tabela a seguir pode ter Hoje a 90 dias atrás. A última mesa poderia TUDO.
FrustratedWithFormsDesigner
Se entendi direito, você está dizendo para replicar a tabela, mas com diferentes coberturas de período. Portanto, se alguém solicitar um relatório de 7 dias, será utilizada uma tabela que remonta apenas uma semana. Se eles expandissem para 8 dias, a tabela seguinte seguinte (por exemplo, 30 dias) seria utilizada? Isso certamente melhoraria a velocidade das consultas de menor duração, mas com um custo de armazenamento (barato) e lógica de programação para lidar com as tabelas em camadas (não tão baratas).
27412 JYelton
@JYelton: Sim, acho que você entendeu corretamente. Se os intervalos de tempo da consulta forem padrão (hoje - 1 dia, hoje - 7 dias, hoje - 30 dias, hoje - 90 dias), não acho que será muito difícil, pois você sempre saberá qual tabela usar bater. Se os intervalos de tempo puderem ter uma duração variável, onde o início do intervalo pode não ser a data atual, você está correto, a lógica a ser implementada será complicada e as consultas de tabelas cruzadas podem ficar caras com as operações UNION em várias tabelas.
FrustratedWithFormsDesigner