O cenário é que eu tenho um conjunto crescente de usuários e, com o passar do tempo, os usuários cancelam suas contas que atualmente marcamos como 'excluídas' (com um sinalizador) na mesma tabela.
Se usuários com o mesmo endereço de e-mail (é assim que os usuários fazem login) desejam criar uma nova conta, eles podem se inscrever novamente, mas uma NOVA conta é criada. (Como temos identificações únicas para cada conta, os endereços de e-mail podem ser duplicados entre os ativos e os excluídos).
O que eu notei é que em todo o sistema, no curso normal das coisas, consultamos constantemente a tabela de usuários, verificando se o usuário não é excluído, enquanto o que estou pensando é que não precisamos fazer isso ... ! [Esclarecimento1: ao 'consultar constantemente', quis dizer que temos consultas como: '... FROM users WHERE isdeleted = "0" AND ...'. Por exemplo, talvez seja necessário buscar todos os usuários registrados para todas as reuniões em uma data específica; portanto, nessa consulta, também temos FROM usuários WHERE isdeleted = "0" - isso torna meu argumento mais claro?]
(1) continue keeping deleted users in the 'main' users table
(2) keep deleted users in a separate table (mostly required for historical
book-keeping)
Quais são os prós e os contras de qualquer uma das abordagens?
fonte
Respostas:
Você pode usar, por exemplo, um gatilho para mover automaticamente os usuários excluídos para a tabela de histórico.
fonte
Eu recomendo usar a mesma tabela. O principal motivo é a integridade dos dados. Provavelmente, haverá muitas tabelas com relacionamentos, dependendo dos usuários. Quando um usuário é excluído, você não deseja deixar esses registros órfãos.
Ter registros órfãos dificulta a aplicação de restrições e torna mais difícil a busca de informações históricas. O outro comportamento a considerar se, quando um usuário fornecer um email usado, se você desejar recuperar todos os registros antigos. Isso funcionaria automaticamente usando a exclusão suave. Quanto à codificação, por exemplo, no meu aplicativo c # linq atual, a cláusula where delete = 0 é automaticamente anexada ao final de todas as consultas
fonte
Isso me dá um cheiro ruim de design. Você deve esconder esse tipo de lógica. Por exemplo, você deve
UserService
fornecer um métodoisValidUser(userId)
para uso "em todo o sistema", em vez de fazer algo como:Sua maneira de armazenar usuários excluídos não deve afetar a lógica de negócios.
Com esse tipo de encapsulamento, o argumento acima não deve mais afetar a abordagem de sua persistência. Então você pode se concentrar mais nos prós e contras relacionados à própria persistência.
As coisas a considerar incluem:
Normalmente, eu adotaria uma maneira combinada:
fonte
Para responder adequadamente a essa pergunta, primeiro você precisa decidir: O que "excluir" significa no contexto deste sistema / aplicativo?
Para responder a essa pergunta, você precisa responder a outra pergunta: Por que os registros estão sendo excluídos?
Existem várias boas razões pelas quais um usuário pode precisar excluir dados. Normalmente, acho que há exatamente uma razão (por tabela) para a exclusão de uma exclusão. Alguns exemplos são:
Há também algumas razões muito ruins para exclusão completa (mais sobre as razões para isso posteriormente):
Por que, você pergunta, é realmente tão importante? O que há de errado com o bom e velho
DELETE
?Então, a exclusão suave é melhor, certo? Não, na verdade não:
A verdade é que ambas as abordagens estão erradas. A exclusão está errada. Se você está realmente fazendo essa pergunta, significa que está modelando o estado atual em vez das transações. Essa é uma prática ruim e ruim na área de banco de dados.
Udi Dahan escreveu sobre isso em Não Excluir - Apenas Não . Há sempre algum tipo de tarefa, operação, atividade , ou (o meu preferido prazo) evento que realmente representa o "delete". Tudo bem se você desejar desnormalizar posteriormente em uma tabela de "estado atual" para desempenho, mas faça isso depois de definir o modelo transacional, não antes.
Nesse caso, você tem "usuários". Usuários são essencialmente clientes. Os clientes têm um relacionamento comercial com você. Esse relacionamento não simplesmente desaparece no ar porque eles cancelaram sua conta. O que realmente está acontecendo é:
Em todos os casos, é o mesmo cliente e, possivelmente, a mesma conta (ou seja, cada renovação de conta é um novo contrato de serviço). Então, por que você está excluindo linhas? Isso é muito fácil de modelar:
É isso aí. É tudo o que há para isso. Você nunca precisa excluir nada. O acima é um design bastante comum que acomoda um bom grau de flexibilidade, mas você pode simplificá-lo um pouco; você pode decidir que não precisa do nível "Contrato" e fazer com que "Conta" vá para uma tabela "Status da conta".
Se uma necessidade frequente em seu aplicativo é obter uma lista de contratos / contas ativos , é uma consulta (um pouco) complicada, mas é para isso que servem as visualizações:
E você terminou. Agora você tem algo com todos os benefícios das exclusões eletrônicas, mas nenhuma das desvantagens:
O único problema a ser resolvido é o problema de desempenho. Em muitos casos, na verdade, não é um problema por causa do índice clusterizado
AgreementStatus (AgreementId, EffectiveDate)
- há muito pouca procura de E / S lá. Mas, se houver algum problema, há maneiras de resolver isso, usando gatilhos, visualizações indexadas / materializadas, eventos no nível do aplicativo, etc.Porém, não se preocupe com o desempenho muito cedo - é mais importante acertar o design e, "nesse caso", significa usar o banco de dados da maneira que um banco de dados deve ser usado, como um sistema transacional .
fonte
Atualmente, estou trabalhando com um sistema no qual todas as tabelas possuem um sinalizador Excluído para exclusão reversa. É a desgraça de toda a existência. Ele quebra totalmente a integridade relacional quando um usuário pode "excluir" um registro de uma tabela, mas os registros filhos que FK retornam a essa tabela não são excluídos em cascata. Realmente cria dados de lixo após o tempo passar.
Portanto, recomendo tabelas de histórico separadas.
fonte
Quebrar a mesa ao meio seria a coisa mais lamentável que se possa imaginar.
Aqui estão as duas etapas muito simples que eu recomendaria:
PS Desculpe pelo atraso de vários meses em responder!
fonte
Se você estivesse recuperando contas excluídas quando alguém voltasse com o mesmo endereço de e-mail, eu teria mantido todos os usuários na mesma tabela. Isso tornaria o processo de recuperação da conta trivial.
No entanto, à medida que você cria novas contas, provavelmente seria mais simples mover as contas excluídas para uma tabela separada. O sistema ativo não precisa dessas informações, portanto, não as exponha. Como você diz, as consultas são mais simples e possivelmente mais rápidas em conjuntos de dados maiores. Código mais simples também é mais fácil de manter.
fonte
Você não menciona o DBMS em uso. Se você possui o Oracle com licença adequada, considere particionar a tabela de usuários em duas partições: usuários ativos e excluídos.
fonte