Galera, gostaria de saber se é possível manter uma tabela dentro do banco de dados que se manteria baseada em outra tabela.
Por exemplo,
Tabela Valores
Id | Data | Valor
1 | 01/11/2017 | 1000
2 | 01/11/2017 | 2000
1 | 05/11/2017 | 1400
3 | 07/11/2017| 1500
1 | 01/12/2017| 1500
2 | 03/12/2017| 1600
3 | 01/11/2017| 1800
Tabela SomaValores:
Id | Mes | SomaValor
1 | Novembro | 2400
E assim por diante..
Eu sei que é redundante, mas a tabela de valores teriam muitos dados e a consunta aos seus valores por mês seria a todo momento, o que faria com que o BD ficaria lento por conta da proporção de dados.
A minha ideia foi criar uma redundância, até eu sei que é possível, mas minha duvida vem se é possível criar um script que ao entrar um novo valor na tabela Valores, esse valor seja acrescentado direto na tabela SomaValores sem que eu tenha que percorrer TODA a tabela valores novamente, (o script iria se basear apenas em novas inserções na tabela valores e acrescentar na tabela somavalores)
Cria um trigger que será disparado sempre que houver um insert/update/delete na tabela de valores, onde o trigger deve atualizar o valor do mês referente na tabela soma valores.
Você já tentou criar um índice na coluna ‘Data’ ? Eu acho que seria bem mais efetivo e simples de manter do que criar essa redundância. Além disso, se você incluir o campo do valor que vai ser somado no índice, da seguinte maneira:
create index idx_tabela on tabela_valores(Data, Valor)
e consultar da seguinte maneira:
--sintaxe do PostgreSQL
select date_part('month', Data), sum(Valor)
from tabela_valores
where Data between '2017-12-01' and '2017-12-31'
group by date_part('month', Data)
você vai poder consultar milhões de linhas tranquilamente, pois além de filtrar as datas pelo índice, a sua consulta não precisará ler as linhas da tabelas do disco. Você vai fazer a consulta completa apenas usando o índice.
Não havia pensado nessa possibilidade, mas o BD não iria sofrer menos com uma trigger que seria utilizada somente uma vez quando houvesse uma inserção de dados de 1000 linhas, do que sempre ter que fazer busca em mais de 300 mil linhas? Mesmo que se tenha um índice das datas ele também teria o gasto de tratar a informação sempre.
No caso do uso de trigger no momento em que ocorre cada insert ele seria disparado, onde é possível você manipular tanto os novos valores que estão sendo inseridos, como também os valores antigos que já existiam na tabela, aí tudo depende de como você quer estruturar o seu trigger.
Só por curiosidade, você está tentando otimizar o tempo de resposta de uma consulta, geração de um relatório ou algo do tipo ?
Seria para geração de um relatório que seria emitido a todo momento, porém ele busca uma quantidade muito grande de dados, ai estava pensando na redundância para otimizar o tempo
Cara, 300 mil linhas para um índice é brincadeira de criança. Além disso, o índice serve justamente para isso, para não percorrer todas as linhas de uma tabela em busca de um resultado. O tempo de busca em um índice é de ordem logarítmica, ou seja, para 300k de linhas o seu tempo seria proporcional a log2(300.000) ~ 18. Ou seja, seria o equivalente a percorrer 18 linhas de maneira linear.
Você só precisa tomar cuidado com a condição WHERE do seu relatório, um operador do tipo OR mal planejado pode colocar a perder todo o seu esforço de otimização. Mas eu volto a repetir: 300k de linhas para um banco relacional está muito longe ser quantidade grande de dados. Uma query + índice bem planejados vai funcionar muito bem.
Vi agora o código que você postou, o exemplo que eu coloquei é simples, mas no relatório teria que trazer quase todas as colunas que teriam no BD, então não seria possível utilizar o índice da maneira com que você colocou. Sendo necessário ler as linhas da tabela, mesmo dessa forma seria mais eficiente do que uma trigger?
De acordo com o que o @rmendes08 disse sobre criar um índice na coluna de data, de repente a criação de uma view indexada te traga um ganho no desempenho/tempo na geração do seu relatório.
Faça os testes e veja qual solução se torna mais viável para o seu problema.
Sim. Colocar a coluna de valor junto no índice seria apenas um “plus”, mas mesmo que não seja possível, ainda sim o índice é a solução mais recomendada. Mas como eu disse a cláusula WHERE deve ser analisada com cuidado. Uma boa maneira de testar a sua query e verificar se o índice está sendo efetivamente usado é verificar o PLANO DE EXECUÇÃO da query. Procure na sua IDE de banco de dados que com certeza existe essa opção. Verificando o plano de execução você vai saber se o índice está sendo usado para filtrar os dados ou se o BD está executando um FULL TABLE SCAN. Por fim, indico a leitura: