Em um projeto em que estou trabalhando, todas as alterações nas linhas em algumas tabelas do banco de dados devem ser rastreadas para posterior auditoria ou reversão. Deve ser fácil encontrar quem modificou a linha, a partir de qual endereço IP e quando, além de poder restaurar a versão anterior.
A mesma coisa é usada, por exemplo, pelo Stack Exchange. Quando altero a pergunta de outra pessoa, é possível descobrir que a alterei e reverter as alterações.
Qual é a técnica geral usada para armazenar todas as alterações em um objeto em um banco de dados , considerando que meu esquema atual tem basicamente as mesmas propriedades (abaixo) que um aplicativo comercial médio?
- Os objetos têm um tamanho relativamente pequeno: pode haver alguns,
nvarchar(1000)
por exemplo, mas não enormes blobs de dados binários, sendo armazenados diretamente no disco e acessados diretamente, e não através do Microsoft SQLfilestream
, - A carga do banco de dados é bastante baixa e o banco de dados inteiro é tratado por uma máquina virtual em um servidor,
- O acesso às versões anteriores não precisa ser tão rápido quanto o acesso à versão mais recente, mas ainda precisa estar atualizado¹ e não muito lento².
<tl-dr>
Pensei nos seguintes casos, mas não tenho experiência real com esse tipo de cenário, para ouvir as opiniões de outros:
Armazene tudo na mesma tabela, distinguindo as linhas por ID e versão. OMI, é seriamente estúpido e prejudicará mais cedo ou mais tarde o nível de desempenho. Com essa abordagem, também é impossível definir um nível de segurança diferente para os itens mais recentes e para o rastreamento de versões. Finalmente, toda consulta seria mais complicada de escrever. Na verdade, para acessar os dados atualizados, eu seria forçado a agrupar tudo por ID e recuperar, em cada grupo, a última versão.
Armazene a versão mais recente em uma tabela e, a cada alteração, copie a versão obsoleta para outra tabela em outro esquema. A falha é que sempre armazenamos todos os valores, mesmo que não tenham mudado. Definir valores inalterados como
null
não é uma solução, pois também devo rastrear quando o valor é alterado paranull
ou denull
.Armazene a versão mais recente em uma tabela e a lista de propriedades alteradas com seus valores anteriores em outra tabela. Isso parece ter duas falhas: a mais importante é que a única maneira de classificar tipos heterogêneos de valores anteriores na mesma coluna é ter a
binary(max)
. A segunda é que, acredito, seria mais difícil usar essa estrutura ao exibir as versões anteriores para o usuário.Faça o mesmo que nos dois pontos anteriores, mas armazene as versões em um banco de dados separado. Em termos de desempenho, pode ser interessante para evitar a lentidão do acesso às versões mais recentes, tendo as versões anteriores no mesmo banco de dados; ainda assim, acredito que seja uma otimização prematura e deve ser feita apenas se houver uma prova de que ter versões mais antigas e mais recentes no mesmo banco de dados é um gargalo.
</tl-dr>
¹ Por exemplo, seria inaceitável armazenar as alterações em um arquivo de log, como é feito nos logs HTTP, e liberar os dados do log para o banco de dados à noite, quando a carga do servidor for menor. As informações sobre diferentes versões devem estar disponíveis imediatamente ou quase imediatamente; um atraso de alguns segundos é aceitável.
² As informações não são acessadas com muita frequência e apenas por um grupo específico de usuários, mas, ainda assim, seria inaceitável forçá-los a aguardar 30 segundos pela exibição da lista de versões. Mais uma vez, é aceitável um atraso de alguns segundos.