Me pediram para criar algo que rastreie o custo diário a ser cobrado nas contas e estou tentando descobrir um esquema de tabela de banco de dados que suporte isso.
Aqui está o que eu sei
- A empresa possui mais de 2,5 milhões de contas
- Destes, eles trabalham atualmente em média 200.000 por mês (que muda com os níveis de pessoal, que atualmente são baixos)
- Eles têm 13 tipos de custo diferentes que gostariam de acompanhar e alertaram que podem adicionar mais no futuro
- Eles querem que os custos sejam rastreados diariamente
- Os custos não são divididos em todo o inventário. Eles são divididos pelo número de contas trabalhadas por mês (200.000), ou os usuários podem inserir identificadores de conta para aplicar um custo a um grupo de contas ou podem simplesmente especificar em quais contas aplicar o custo.
Meu primeiro pensamento foi um banco de dados normalizado:
AccountId Encontro CostTypeId Montante
Meu problema com isso é: faça as contas. Essa tabela ficará enorme rapidamente. Supondo que todos os 13 tipos de custo sejam aplicados a todas as contas trabalhadas do mês atual, isso 200k * 13 * N days in month
é algo em torno de 75 a 80 milhões de registros por mês ou quase um bilhão de registros por ano.
Meu segundo pensamento foi desnormalizar um pouco
AccountId Encontro Custo total CostType1 CostType2 CostType3 CostType4 CostType5 CostType6 CostType7 CostType8 CostType9 CostType10 CostType11 CostType12 CostType13
Esse método é mais desnormalizado e pode criar até 6 milhões de registros por mês ( 200k * N days in month
), ou cerca de 72 milhões por ano. É muito menor que o primeiro método, no entanto, se a empresa decidir sobre um novo Tipo de Custo no futuro, outra coluna do banco de dados precisará ser adicionada.
Dos dois métodos, qual você prefere? Por quê? Existe outra alternativa que você possa imaginar que lidaria melhor com isso?
Estou mais interessado em relatar o desempenho, tanto no verão quanto nos detalhados. O trabalho que distribuirá os custos pelas contas será executado todas as noites quando não houver ninguém por perto. Uma preocupação secundária é o tamanho do banco de dados. O banco de dados existente já tem quase 300 GB e acredito que o espaço em disco seja de cerca de 500 GB.
O banco de dados é SQL Server 2005
Respostas:
Um bilhão de registros por ano não é muito.
Com o particionamento (por Costtype, talvez) e o arquivamento, é gerenciável.
O número de itens de dados a serem armazenados ainda é 200k * 13 * N. Como colunas, você obterá menos linhas por página e ocupará mais espaço do que como linhas. Você pode ganhar se "CostType1" não for um tipo de dados de comprimento fixo, mas for marginal.
"KISS" como se costuma dizer
fonte
Embora seu design possa certamente fazer a diferença de noite ou dia, nesse caso, eu me concentraria mais em índices, incluindo a cobertura de índices conforme necessário. Também examinaria algumas das ferramentas que o SQL Server fornece para lidar com tabelas muito grandes, como particionamento de tabelas.
Pense dessa maneira, mesmo que haja 80 bilhões de registros na tabela, com indexação adequada, aqueles em que você realmente se interessa em um determinado momento serão agrupados fisicamente em disco. Devido à maneira como os dados são organizados no SQL Server, os dados divididos por limites de índice também podem estar em outra tabela, pois não precisam ler a tabela inteira para obter o que precisam.
Se você também optar por particionar a tabela, poderá melhorar o tempo de acesso e inserir o tempo.
fonte
Eu normalizaria. Realizamos a contabilidade de custos da lucratividade da conta do cliente em um banco e geramos mais de 250 milhões de linhas de custos individuais usando centenas de drivers alocados por centro de custo ou contabilidade, ou por várias outras técnicas em milhões de contas todos os meses.
Por exemplo, o custo total de atendimento aos caixas eletrônicos foi dividido entre as contas que usaram caixas eletrônicos com base na quantidade relativa de uso. Portanto, se US $ 1 milhão foi gasto em serviços de caixas eletrônicos e apenas 5 clientes o usaram uma vez cada e um cliente o utilizou 5 vezes, esse cliente custou ao banco US $ 0,5 milhão e os outros clientes custaram US $ 0,1 milhão ao banco. Outros drivers podem ser muito mais complexos.
Por fim, você provavelmente achará escasso - certas contas não obtêm custos de determinadas fontes / drivers - e algumas contas não obtêm nada. Em um modelo normalizado, essas linhas não existem. No modelo desnormalizado, a linha existe, com algumas colunas vazias. Além disso, em um modelo normalizado esparso, você deve ver o desempenho melhorar, porque a existência de uma linha é geralmente mais rápida de verificar (com índice de cobertura no CostType) do que verificar todas as linhas com não NULL em um determinado "bucket" (mesmo com índices em cada coluna de valor - que você pode ver começa a ficar muito desperdiçada).
fonte
Independentemente do benefício de desempenho, eu definitivamente seria a favor da opção 1. A opção 2 estaria roubando Peter para pagar a Paul, na minha opinião.
fonte
Eu usaria a opção 1 e, se a velocidade do relatório se tornasse um problema no futuro, eu também adicionaria a tabela 2 e a preencheria em um banco de dados de relatórios em algum tipo de processo automatizado durante a noite / offpeak.
Você também pode considerar a agregação da estrutura diária da tabela 2 em acumulações adicionais semanais, mensais, trimestrais e anuais, se necessário.
Mas, como eu disse, também escolheria armazenar os dados 'brutos' na forma adequada (normalizada).
fonte
Considerando os volumes mencionados, eu optaria pela segunda opção, mas sem o TotalCost. Você poderia dizer que ainda está normalizado.
Editar: como alternativa, e dependendo dos seus requisitos e do tamanho do AccountId, você também pode considerar o seguinte:
Com esse design, você ainda pode adicionar um TotalCost desnormalizado à primeira tabela e recalculá-lo todas as noites, permitindo executar alguns relatórios somente na primeira tabela.
fonte
TotalCost
lá porque a maioria dos relatórios é resumida e achei que seria mais rápido consultar um único valor do que adicionar 13 valores diferentes.na verdade, você deve dividir a tabela de abas em duas tabelas para poder usar uma subconsulta e selecionar a segunda linha como uma coluna ou várias colunas. é mais flexível dessa maneira e com isso, você pode obter um resultado como o segundo mais facilmente.
fonte