Design do banco de dados - Armazene estado ou calcule o estado toda vez?

15

Digamos que eu tenha um aplicativo de banco de dados relacional e um objeto "user" e um objeto "message". Agora quero mostrar o número de mensagens não lidas para esse usuário.

Qual é a melhor maneira de arquivar isso? Introduzo um campo no usuário e faço a contagem se o usuário receber uma mensagem e diminuir a contagem se ele ler uma? Ou eu executo uma consulta toda vez para calcular o número de mensagens para o usuário que estão marcadas como não lidas?

Acho que a primeira abordagem é mais complicada e propensa a erros, mas terá um desempenho melhor do que a segunda abordagem.

Como isso é feito normalmente ou qual é a melhor abordagem?

    
por jan 24.06.2014 / 12:31
fonte

4 respostas

14

How is this normally done or whats the better approach?

A melhor abordagem é tentar primeiro sem um campo extra, medir o desempenho e, se realmente for muito lento, você tenta otimizar. Isso pode significar mudar para sua primeira abordagem usando um campo extra, mas você deve considerar testar outras opções também, por exemplo, colocando um índice extra nos campos combinados ("não-lidos", "userID") em suas mensagens. / p>     

por 24.06.2014 / 12:48
fonte
9

A solução de livros didáticos de acordo com a teoria do banco de dados seria não ter valores em seu banco de dados que dependam dos valores de outros dados, porque estes são dependências transitivas . Ter campos que são valores calculados com base em outros campos é uma violação da normalização, porque leva a informações redundantes.

No entanto, às vezes o que o livro diz e qual é o método mais prático na prática é diferente. Contar o número de mensagens não lidas cada exibição de página pode ser uma operação bastante cara. Armazenar em cache o número na tabela user seria muito melhor para o desempenho. O custo seria que seja possível haver inconsistências no banco de dados: pode ser possível que uma mensagem seja excluída, adicionada ou lida sem lembrar de atualizar também o contador não lido.

    
por 24.06.2014 / 13:03
fonte
4

O possível problema é o desempenho e você ainda não tem um problema de desempenho. Há muitas coisas que você pode fazer dependendo do banco de dados escolhido para lidar com isso na solução # 1: indexação, hardware, armazenamento em cache, etc. Tudo depende da frequência com que o usuário precisa obter uma contagem atual de mensagens não lidas. Muitas dessas opções não exigem codificação personalizada no lado do aplicativo, para que você possa implementá-las com uma alteração de código ou muito pouco. Facilita o crescimento com o aplicativo.

Quando um usuário se conecta / efetua login, obter a contagem do banco de dados uma vez não é tão ruim assim. Seu aplicativo manterá uma lista constantemente atualizada de mensagens como e-mail? Conseguir uma contagem não lida daqui não requer outra viagem para o banco de dados e para obter novas mensagens vai levar uma viagem de banco de dados de qualquer maneira.

Fazer uma viagem ao banco de dados sempre que uma mensagem é lida para sinalizar o IsRead? campo é suficiente sem um recálculo de outro campo.

Com a solução # 2 (mantendo uma contagem em um campo / disco), você precisará de uma rotina para reconstruir / recalcular periodicamente este campo quando houver um problema? E sempre há problemas. Você vai envolver tudo isso em uma transação? Toda vez que alguém envia uma mensagem para outra pessoa, ela pode falhar porque não pode atualizar a UnreadCount do usuário destinatário devido a um bloqueio da tabela Usuário? Ou você vai criar uma tabela separada para este campo?

    
por 24.06.2014 / 13:55
fonte
0

A maneira que eu faria é executar uma consulta toda vez, ou seja, sua segunda abordagem. Apenas certifique-se de adicionar um índice em sua tabela de mensagens na coluna que atua como uma chave estrangeira para a tabela de usuários para melhorar o desempenho de sua consulta.

Então, conforme Doc diz, meça o desempenho dessa abordagem e, em seguida, você será capaz de dizer se precisa seguir um caminho diferente.

    
por 24.06.2014 / 12:54
fonte