Qual é a vantagem de fazer uma exclusão lógica / suave de um registro (ou seja, definir um sinalizador informando que o registro foi excluído) em vez de excluir real ou fisicamente o registro?
Esta é uma prática comum?
Isso é seguro?
Qual é a vantagem de fazer uma exclusão lógica / suave de um registro (ou seja, definir um sinalizador informando que o registro foi excluído) em vez de excluir real ou fisicamente o registro?
Esta é uma prática comum?
Isso é seguro?
Respostas:
As vantagens são que você mantém o histórico (bom para auditoria) e não precisa se preocupar com uma exclusão em cascata por meio de várias outras tabelas no banco de dados que fazem referência à linha que você está excluindo. A desvantagem é que você deve codificar quaisquer métodos de relatório / exibição para levar o sinalizador em consideração.
No que diz respeito a se for uma prática comum - eu diria que sim, mas como em qualquer coisa, se você vai usá-la depende das necessidades do seu negócio.
EDIT: Pense em outra desvantagem - Se você tiver índices exclusivos na tabela, os registros excluídos ainda ocuparão o registro "um", então você também deve codificar essa possibilidade (por exemplo, uma tabela de usuário que tem um índice exclusivo em nome de usuário; Um registro excluído ainda bloquearia o nome de usuário do usuário excluído para novos registros. Ao contornar isso, você poderia adicionar um GUID à coluna de nome de usuário excluído, mas é uma solução alternativa muito hacky que eu não recomendaria. Provavelmente, nessa circunstância, seria melhor apenas ter uma regra de que uma vez que um nome de usuário é usado, ele nunca pode ser substituído.)
CREATE UNIQUE INDEX ... WHERE DELETED_AT is null
(no PostgreSQL) e então todas as linhas com qualquer data de exclusão não são indexadas. (Eles podem ser incluídos em um índice não exclusivo.)
As exclusões lógicas são uma prática comum? Sim, eu vi isso em muitos lugares. Eles estão seguros? Isso realmente depende se eles são menos seguros do que os dados eram antes de você excluí-los?
Quando eu era um líder técnico, exigi que nossa equipe mantivesse todos os dados, eu sabia na época que usaríamos todos esses dados para construir vários aplicativos de BI, embora na época não soubéssemos quais seriam os requisitos estar. Embora isso fosse bom do ponto de vista de auditoria, solução de problemas e relatórios (este era um site de comércio eletrônico / ferramentas para transações B2B, e se alguém usasse uma ferramenta, queríamos registrá-lo mesmo que sua conta fosse desativada posteriormente), ele teve várias desvantagens.
As desvantagens incluem (não incluindo outras já mencionadas):
Ao decidir usar exclusões lógicas, físicas ou arquivamento, eu me perguntaria o seguinte:
Activated
table and Deactivated
table schema - Id,Name,etc..
Row in Activated
- 1001,Smith007,etc...
Quando ele está desativado, podemos limpar tudo, exceto a coluna ID para smith in Activated
e adicioná-lo a Deactivated
.
Pode ser um pouco tarde, mas sugiro que todos verifiquem a postagem do blog de Pinal Dave sobre exclusão lógica / suave:
Eu simplesmente não gosto desse tipo de design [soft delete]. Acredito firmemente na arquitetura em que apenas os dados necessários devem estar em uma única tabela e os dados inúteis devem ser movidos para uma tabela arquivada. Em vez de seguir a coluna isDeleted, sugiro o uso de duas tabelas diferentes: uma com pedidos e outra com pedidos excluídos. Nesse caso, você terá que manter ambas as tabelas, mas na realidade, é muito fácil de manter. Quando você escreve a instrução UPDATE na coluna isDeleted, escreva INSERT INTO em outra tabela e DELETE da tabela original. Se a situação for de rollback, escreva outro INSERT INTO e DELETE na ordem inversa. Se você está preocupado com uma transação falhada, envolva este código em TRANSACTION.
Quais são as vantagens da mesa menor em relação à mesa maior nas situações descritas acima?
- Uma mesa menor é fácil de manter
- As operações de reconstrução do índice são muito mais rápidas
- Mover os dados do arquivo para outro grupo de arquivos reduzirá a carga do grupo de arquivos primário (considerando que todos os grupos de arquivos estão em sistemas diferentes) - isso também acelerará o backup.
- As estatísticas serão atualizadas com frequência devido ao tamanho menor e isso exigirá menos recursos.
- O tamanho do índice será menor
- O desempenho da mesa melhorará com um tamanho de mesa menor.
Sou desenvolvedor NoSQL e no meu último trabalho trabalhei com dados que sempre foram críticos para alguém, e se foram deletados por acidente no mesmo dia da criação, não consegui encontrar no último backup de ontem! Nessa situação, a exclusão suave sempre salvou o dia.
Fiz soft-deletion usando timestamps, registrando a data em que o documento foi excluído:
IsDeleted = 20150310 //yyyyMMdd
Todo domingo, um processo caminhava no banco de dados e verificava o IsDeleted
campo. Se a diferença entre a data atual e o carimbo de data / hora fosse maior que N dias, o documento foi excluído definitivamente. Considerando que o documento ainda está disponível em algum backup, foi seguro fazê-lo.
EDITAR: Este caso de uso NoSQL é sobre grandes documentos criados no banco de dados, dezenas ou centenas deles todos os dias, mas não milhares ou milhões. Em geral, eram documentos com o status, dados e anexos de processos de workflow. Por isso havia a possibilidade de um usuário deletar um documento importante. Este usuário pode ser alguém com privilégios de administrador, ou talvez o proprietário do documento, apenas para citar alguns.
TL; DR Meu caso de uso não era Big Data. Nesse caso, você precisará de uma abordagem diferente.
Um padrão que usei é criar uma tabela de espelho e anexar um gatilho na tabela primária, de forma que todas as exclusões (e atualizações, se desejado) sejam registradas na tabela de espelho.
Isso permite que você "reconstrua" registros apagados / alterados, e você ainda pode deletar fisicamente na tabela primária e mantê-la "limpa" - também permite a criação de uma função "desfazer", e você também pode registrar a data, hora , e o usuário que executou a ação na mesa espelho (inestimável em situações de caça às bruxas).
A outra vantagem é que não há chance de incluir acidentalmente registros excluídos ao consultar o primário, a menos que você deliberadamente se dê ao trabalho de incluir registros da tabela espelho (você pode querer mostrar registros ativos e excluídos).
Outra vantagem é que a tabela espelho pode ser eliminada de forma independente, já que não deve ter nenhuma referência de chave estrangeira real, tornando esta operação relativamente simples em comparação com a eliminação de uma tabela primária que usa exclusões suaves, mas ainda tem conexões referenciais com outras tabelas.
Que outras vantagens? - ótimo se você tem um monte de programadores trabalhando no projeto, fazendo leituras no banco de dados com habilidade mista e atenção aos níveis de detalhes, você não precisa ficar acordado noites esperando que um deles não se esqueça de não incluir os excluídos registros (risos, não incluir registros excluídos = verdadeiro), o que resulta em coisas como exagero, digamos, a posição de caixa disponível do cliente com a qual eles vão comprar algumas ações (ou seja, como em um sistema de negociação), quando você trabalha com sistemas de negociação, você irá descobrir rapidamente o valor de soluções robustas, mesmo que elas possam ter um pouco mais de "overhead" inicial.
Exceções:
- como guia, use exclusões reversíveis para dados de "referência", como usuário, categoria, etc., e exclusões permanentes em uma tabela espelho para dados do tipo "fato", ou seja, histórico de transações.
Eu costumo usar exclusões lógicas - acho que elas funcionam bem quando você também arquiva intermitentemente os dados 'excluídos' em uma tabela arquivada (que pode ser pesquisada se necessário), portanto, sem chance de afetar o desempenho do aplicativo.
Funciona bem porque você ainda tem os dados, caso seja auditado. Se você excluí-lo fisicamente, ele se foi !
Sou um grande fã da exclusão lógica, especialmente para um aplicativo de linha de negócios ou no contexto de contas de usuário. Meus motivos são simples: muitas vezes eu não quero que um usuário possa mais usar o sistema (então a conta é marcada como excluída), mas se excluíssemos o usuário, perderíamos todo o seu trabalho e tal.
Outro cenário comum é que os usuários podem ser recriados um tempo após terem sido excluídos. É uma experiência muito mais agradável para o usuário ter todos os seus dados presentes como estavam antes de serem excluídos, em vez de ter que recriá-los.
Geralmente penso em excluir usuários mais como "suspendê-los" indefinidamente. Você nunca sabe quando eles precisam legitimamente estar de volta.
Quase sempre faço soft delete e aqui está o motivo:
isdeleted
todos os lugares não é um problema, você deve verificar de userid
qualquer maneira (se o banco de dados contiver dados de vários usuários). Você pode impor a verificação por código, colocando essas duas verificações em uma função separada (ou usar visualizações)Re: "Isso é seguro?" - isso depende do que você quer dizer.
Se você quer dizer que ao fazer exclusão física, você impedirá que alguém encontre os dados excluídos , então sim, isso é mais ou menos verdade; você está mais seguro ao excluir fisicamente os dados confidenciais que precisam ser apagados, porque isso significa que eles desapareceram permanentemente do banco de dados. (No entanto, perceba que pode haver outras cópias dos dados em questão, como em um backup, ou o log de transações, ou uma versão gravada em trânsito, por exemplo, um farejador de pacotes - só porque você excluiu do seu banco de dados não garantir que não foi salvo em outro lugar.)
Se você quer dizer que, ao fazer uma exclusão lógica, seus dados ficarão mais seguros porque você nunca perderá nenhum dado , isso também é verdade. Isso é bom para cenários de auditoria; I tendem a projetar desta forma porque admite o fato básico de que uma vez que os dados são gerados, isso nunca vai realmente ir embora (especialmente se já teve a capacidade de ser, digamos, em cache por um motor de busca na Internet). Obviamente, um cenário de auditoria real requer que não apenas as exclusões sejam lógicas, mas que as atualizações também sejam registradas, junto com a hora da mudança e o ator que fez a mudança.
Se você quer dizer que os dados não cairão nas mãos de alguém que não deveria vê-los, isso depende totalmente de seu aplicativo e de sua estrutura de segurança. Nesse sentido, a exclusão lógica não é mais nem menos segura do que qualquer outra coisa em seu banco de dados.
Eu discordo veementemente da exclusão lógica porque você está exposto a muitos erros.
Antes de mais nada, cada consulta deve atender ao campo IsDeleted e a possibilidade de erro torna-se maior com consultas complexas.
Segundo a performance: imagine uma mesa com 100.000 recs com apenas 3 ativos, agora multiplique este número pelas tabelas do seu banco de dados; outro problema de desempenho é um possível conflito com novos registros com antigos (registros excluídos).
A única vantagem que vejo é o histórico de registros, mas existem outros métodos para alcançar este resultado, por exemplo, você pode criar uma tabela de registro onde você pode salvar informações: TableName,OldValues,NewValues,Date,User,[..]
onde *Values
pode estar varchar
e escrever os detalhes neste formulário fieldname : value
; [..] ou armazene as informações como xml
.
Tudo isso pode ser conseguido via código ou gatilhos, mas você é apenas UMA mesa com todo o seu histórico. Outra opção é ver se o mecanismo de banco de dados especificado tem suporte nativo para rastrear alterações, por exemplo, no banco de dados SQL Server há SQL Track Data Change.
Eu costumava fazer soft-delete, apenas para manter registros antigos. Percebi que os usuários não se preocupam em ver registros antigos com a freqüência que eu pensava. Se os usuários desejam visualizar registros antigos, eles podem apenas visualizar do arquivo ou da tabela de auditoria, certo? Então, qual é a vantagem do soft-delete? Isso só leva a instruções de consulta mais complexas, etc.
A seguir estão as coisas que eu implementei, antes de decidir não mais fazer a exclusão reversível:
implementar auditoria, para registrar todas as atividades (adicionar, editar, excluir). Certifique-se de que não há nenhuma chave estrangeira vinculada à auditoria e certifique-se de que esta tabela está protegida e ninguém pode excluir, exceto administradores.
identificar quais tabelas são consideradas "tabela transacional", que muito provavelmente serão mantidas por muito tempo, e muito provavelmente o usuário pode querer ver os registros ou relatórios anteriores. Por exemplo; transação de compra. Essa tabela não deve apenas manter o id da tabela mestre (como dept-id), mas também manter as informações adicionais, como o nome como referência (como dept-name) ou quaisquer outros campos necessários para o relatório.
Implemente o registro "ativo / inativo" ou "habilitar / desabilitar" ou "ocultar / mostrar" da tabela mestre. Assim, em vez de excluir o registro, o usuário pode desabilitar / inativar o registro mestre. É muito mais seguro assim.
Apenas minha opinião de dois centavos.
Exclusões lógicas se forem difíceis para a integridade referencial.
É a coisa certa a se pensar quando há um aspecto temporal dos dados da tabela (são válidos FROM_DATE - TO_DATE).
Caso contrário, mova os dados para uma tabela de auditoria e exclua o registro.
Do lado positivo:
É a maneira mais fácil de reverter (se possível).
É fácil ver qual era o estado em um momento específico.
É bastante normal nos casos em que você gostaria de manter um histórico de algo (por exemplo, contas de usuário como @Jon Dewees menciona). E certamente é uma ótima ideia se houver uma grande chance de os usuários solicitarem as exclusões.
Se você está preocupado com a lógica de filtrar os registros excluídos de suas consultas, ficando confuso e apenas complicando suas consultas, você pode simplesmente construir visualizações que fazem a filtragem para você e usar consultas contra isso. Isso evitará o vazamento desses registros em soluções de relatórios e outros.
Existem requisitos além do design do sistema que precisam ser atendidos. Qual é o requisito legal ou estatutário na retenção de registros? Dependendo do que as linhas estão relacionadas, pode haver uma exigência legal de que os dados sejam mantidos por um determinado período de tempo após serem 'suspensos'.
Por outro lado, o requisito pode ser que, uma vez que o registro seja 'excluído', ele seja verdadeira e irrevogavelmente excluído. Antes de tomar uma decisão, converse com seus stakeholders.
Eles não permitem que o banco de dados funcione como deveria, tornando coisas como a funcionalidade de cascata inúteis.
Para coisas simples, como inserções, no caso de reinserção, o código por trás disso dobra.
Você não pode simplesmente inserir, em vez disso, você deve verificar se há uma existência e inserir se ela não existir antes ou atualizar o sinalizador de exclusão se existir, enquanto também atualiza todas as outras colunas para os novos valores. Isso é visto como uma atualização do log de transações do banco de dados e não como uma nova inserção causando logs de auditoria imprecisos.
Eles causam problemas de desempenho porque as tabelas estão ficando sobrecarregadas com dados redundantes. Ele atrapalha a indexação, especialmente com exclusividade.
Não sou um grande fã de exclusões lógicas.
Para responder ao comentário de Tohid, enfrentamos o mesmo problema em que queríamos persistir o histórico de registros e também não tínhamos certeza se queríamos is_deleted
coluna ou não.
Estou falando sobre nossa implementação python e um caso de uso semelhante que encontramos.
Encontramos https://github.com/kvesteri/sqlalchemy-continuum, que é uma maneira fácil de obter uma tabela de controle de versão para sua tabela correspondente. Mínimo de linhas de código e captura de histórico para adicionar, excluir e atualizar.
Isso serve mais do que apenas is_deleted
coluna. Você sempre pode fazer backref da tabela de versão para verificar o que aconteceu com esta entrada. Se a entrada foi excluída, atualizada ou adicionada.
Dessa forma, não precisávamos ter is_deleted
colunas e nossa função de exclusão era bem trivial. Dessa forma, também não precisamos nos lembrar de marcar is_deleted=False
em nenhuma de nossas APIs.
Exclusão suave é uma prática de programação que está sendo seguida na maioria dos aplicativos quando os dados são mais relevantes. Considere um caso de aplicação financeira em que uma exclusão por engano do usuário final pode ser fatal. Esse é o caso quando a exclusão reversível se torna relevante. Na exclusão reversível, o usuário não está realmente excluindo os dados do registro, em vez de ser sinalizado como IsDeleted como true (por convenção normal).
No EF 6.x ou EF 7 em diante, Softdelete é adicionado como um atributo, mas temos que criar um atributo personalizado por enquanto.
Eu recomendo fortemente SoftDelete em um projeto de banco de dados e é uma boa convenção para a prática de programação.
Na maioria das vezes, o softdeleting é usado porque você não deseja expor alguns dados, mas deve mantê-los por motivos históricos (um produto pode ser descontinuado, então você não quer nenhuma nova transação com ele, mas ainda precisa trabalhar com o histórico da transação de venda). A propósito, alguns estão copiando o valor das informações do produto nos dados da transação de venda em vez de fazer uma referência ao produto para lidar com isso.
Na verdade, parece mais uma reformulação de um recurso visível / oculto ou ativo / inativo. Porque esse é o significado de "excluir" no mundo dos negócios. Eu gostaria de dizer que Exterminadores podem deletar pessoas, mas chefe apenas demiti-los.
Essa prática é um padrão bastante comum e usada por muitos aplicativos por vários motivos. Como não é a única maneira de conseguir isso, você terá milhares de pessoas dizendo que isso é ótimo ou besteira e ambos têm argumentos muito bons.
Do ponto de vista da segurança, SoftDelete não substituirá o trabalho de Auditoria e também não substituirá o trabalho de backup. Se você tem medo de "inserir / excluir entre dois casos de backup", deve ler sobre os Modelos de recuperação completos ou em massa. Admito que o SoftDelete pode tornar o processo de recuperação mais trivial.
Cabe a você saber suas necessidades.
Para dar uma alternativa, temos usuários que usam dispositivos remotos atualizando via MobiLink. Se excluirmos registros no banco de dados do servidor, esses registros nunca serão marcados como excluídos nos bancos de dados do cliente.
Portanto, fazemos ambos. Trabalhamos com nossos clientes para determinar por quanto tempo eles desejam recuperar os dados. Por exemplo, geralmente clientes e produtos estão ativos até que nosso cliente diga que eles deveriam ser excluídos, mas o histórico de vendas é retido apenas por 13 meses e, em seguida, excluído automaticamente. O cliente pode querer manter clientes e produtos excluídos por dois meses, mas manter o histórico por seis meses.
Então, rodamos um script durante a noite que marca as coisas logicamente excluídas de acordo com esses parâmetros e, dois / seis meses depois, qualquer coisa marcada logicamente excluída hoje será excluída de forma permanente.
Estamos menos preocupados com a segurança de dados do que com enormes bancos de dados em um dispositivo cliente com memória limitada, como um smartphone. Um cliente que encomenda 200 produtos duas vezes por semana durante quatro anos terá mais de 81.000 linhas de história, das quais 75% o cliente não liga se vir.
Tudo depende do caso de uso do sistema e de seus dados.
Por exemplo, se você está falando sobre um sistema regulado pelo governo (por exemplo, um sistema em uma empresa farmacêutica que é considerado parte do sistema de qualidade e deve seguir as diretrizes do FDA para registros eletrônicos), então é muito melhor não fazer exclusões rígidas! Um auditor do FDA pode entrar e solicitar todos os registros do sistema relativos ao número do produto ABC-123, e é melhor que todos os dados estejam disponíveis. Se o proprietário do processo de negócios disser que o sistema não deve permitir que ninguém use o número do produto ABC-123 em novos registros, use o método de exclusão reversível para torná-lo "inativo" no sistema, preservando os dados históricos.
No entanto, talvez seu sistema e seus dados tenham um caso de uso como "rastrear o tempo no Pólo Norte". Talvez você faça leituras de temperatura uma vez a cada hora e, no final do dia, agregue uma média diária. Talvez os dados de hora em hora não sejam mais usados após a agregação, e você excluiria definitivamente as leituras de hora depois de criar o agregado. (Este é um exemplo inventado e trivial.)
A questão é que tudo depende do caso de uso do sistema e de seus dados, e não de uma decisão a ser tomada puramente do ponto de vista tecnológico.
Bem! Como todos disseram, depende da situação.
Se você tem um índice em uma coluna como UserName ou EmailID - e você nunca espera que o mesmo UserName ou EmailID seja usado novamente; você pode ir com um soft delete.
Dito isso, sempre verifique se sua operação SELECT usa a chave primária. Se sua instrução SELECT usa uma chave primária, adicionar um sinalizador com a cláusula WHERE não faria muita diferença. Vamos dar um exemplo (Pseudo):
Usuários da tabela (UserID [chave primária], EmailID, IsDeleted)
SELECT * FROM Users where UserID = 123456 and IsDeleted = 0
Esta consulta não fará nenhuma diferença em termos de desempenho, pois a coluna UserID possui uma chave primária. Inicialmente, ele fará a varredura da tabela com base no PK e executará a próxima condição.
Casos em que exclusões reversíveis não funcionam:
Inscrever-se em todos os sites, na maioria das vezes, usa EmailID como sua identificação única. Sabemos muito bem, uma vez que um EmailID é usado em um site como o Facebook, G +, ele não pode ser usado por mais ninguém.
Chega um dia em que o usuário deseja deletar seu perfil do site. Agora, se você fizer uma exclusão lógica, esse usuário não poderá mais se registrar. Além disso, registrar-se novamente usando o mesmo EmailID não significaria restaurar todo o histórico. Todo mundo sabe, deletar significa deletar. Em tais cenários, temos que fazer uma exclusão física. Mas, para manter todo o histórico da conta, devemos sempre arquivar esses registros em tabelas de arquivo ou tabelas excluídas.
Sim, em situações onde temos muitas tabelas estrangeiras, o manuseio é bastante complicado.
Além disso, lembre-se de que exclusões suaves / lógicas aumentarão o tamanho da tabela, portanto, o tamanho do índice.
Já respondi em outro post . No entanto, acho que minha resposta se ajusta melhor à pergunta aqui.
Minha solução prática para soft-delete é arquivar, criando uma nova tabela com as seguintes colunas:
original_id
,table_name
,payload
, (e uma chave `id principal opcional).Onde
original_id
está o id original do registro excluído,table_name
é o nome da tabela do registro excluído ("user"
no seu caso),payload
é a string JSON string de todas as colunas do registro excluído.Eu também sugiro fazer um índice na coluna
original_id
para a última recuperação de dados.Por esta forma de arquivamento de dados. Você terá essas vantagens
- Acompanhe todos os dados do histórico
- Ter apenas um local para arquivar registros de qualquer tabela, independentemente da estrutura da tabela do registro excluído
- Não se preocupe com o índice único na tabela original
- Não se preocupe em verificar o índice estrangeiro na tabela original
- Não há mais
WHERE
cláusula em cada consulta para verificar a exclusãoJá é uma discussão aqui explicando porque a exclusão suave não é uma boa ideia na prática. A exclusão reversível apresenta alguns problemas potenciais no futuro, como a contagem de registros, ...
Aventuras são preservação / perpetuação de dados. Uma desvantagem seria uma diminuição no desempenho ao consultar ou recuperar dados de tabelas com quantidade significativa de exclusões reversíveis. No nosso caso usamos uma combinação de ambos: como outros já mencionaram nas respostas anteriores, soft-delete
users/clients/customers
por exemplo, e hard-delete
em items/products/merchandise
tabelas onde há registros duplicados que não precisam ser mantidos.
Depende do caso, considere o seguinte:
Normalmente, você não precisa fazer uma "exclusão reversível" de um registro. Mantenha-o simples e rápido. por exemplo, excluir um produto que não está mais disponível, para que você não precise verificar se o produto não foi excluído de forma reversível em todo o seu aplicativo (contagem, lista de produtos, produtos recomendados, etc.).
Ainda assim, você pode considerar a "exclusão reversível" em um modelo de data warehouse. por exemplo, você está vendo um recibo antigo de um produto excluído. *