J'aimerais implémenter une fonctionnalité "Annulation de la suppression" dans une application Web, de sorte qu'un utilisateur puisse changer d'avis et récupérer un enregistrement supprimé. Réflexions sur la façon de mettre en œuvre cela? Certaines options que j'ai envisagées consistent en fait à supprimer l'enregistrement en question et à stocker les modifications dans une table d'audit distincte, ou à ne pas supprimer l'enregistrement et à utiliser une colonne booléenne "supprimé" pour le marquer comme supprimé. Cette dernière solution nécessiterait une logique d'application supplémentaire pour ignorer les enregistrements "supprimés" dans des circonstances normales, mais faciliterait beaucoup la mise en œuvre de la récupération des enregistrements du côté de l'application.
44
Réponses:
Oui, je choisirais certainement la deuxième option, mais j'ajouterais un champ de plus un champ de date.
Donc vous ajoutez:
Cela vous laisserait un temps pour l'action de suppression.
Si le temps est inférieur à une heure, on peut récupérer.
Pour vraiment supprimer l’entrée supprimée, créez une procédure stockée qui nettoiera chaque entrée avec delete défini sur true et une heure supérieure à une heure.
L'heure n'est qu'un exemple.
la source
cleaned
ou quelque chose - qui indique que les données associées à cet enregistrement ont été supprimées de manière appropriée et complète. L'enregistrement peut être non supprimé sauf sicleaned
vrai, auquel cas il est irrécupérable.deleted_at
contenant à la fois la sémantique dudelete
booléen et l'delete_date
horodatage. Sideleted_at
est -NULL
gérer le casdelete
estFALSE
etdelete_date
estNULL
,deleted_at
contenant une poignée d'horodatage le casdelete
estTRUE
etdelete_date
contient un horodatage, vous permet d' économiser un temps, le stockage et la logique application.deleted
champ peut améliorer considérablement les performances lorsque vous interrogez des lignes non suppriméesDans nos applications , nous ne sommes pas vraiment quoi que ce soit à un effacement des utilisateurs demandent de toute façon (nos clients sont dans des environnements réglementés où tout peut supprimer potentiellement conduire à des problèmes juridiques).
Nous conservons les anciennes versions dans une table d'audit distincte (donc pour la table some_table où se trouve également une table appelée some_table_audit), qui est identique à la différence qu'un identificateur de version supplémentaire (un horodatage si votre base de données de sauvegarde est suffisamment granulaire, un numéro de version entier). ou UUID qui est une clé étrangère d’une table d’audit général, etc.) et met à jour la table d’audit automatiquement par déclencheur (nous n’avons donc pas besoin de mettre tout le code qui met à jour les enregistrements au courant des exigences de l’audit).
Par ici:
Si vous utilisez un horodatage à la place (ou aussi bien) d'un numéro de version entier, vous pouvez l'utiliser pour supprimer les copies les plus anciennes après un laps de temps défini, si nécessaire. Mais l’espace disque est relativement bon marché de nos jours, donc nous ne le ferions pas, sauf si nous avons des raisons de supprimer d’anciennes données (c’est-à-dire que la réglementation en matière de protection des données stipule que vous devez supprimer les données client après X mois / années).
Cette réponse remonte à quelques années et quelques éléments clés susceptibles d’affecter ce type de planification ont changé depuis. Je n'entrerai pas dans les détails, mais pour le bénéfice des lecteurs de cette page aujourd'hui:
SQL Server 2016 a introduit les "tables temporelles système versionnées" qui font beaucoup de ce travail pour vous, et plus encore, car un bon sucre syntaxique est fourni pour faciliter la construction et la maintenance des requêtes historiques, et coordonne un sous-ensemble de modifications de schéma entre tables de base et d'historique. Ils ne sont pas sans leurs mises en garde, mais ils sont un outil puissant pour ce genre de but. Des fonctionnalités similaires sont également disponibles dans d'autres systèmes de base de données.
Les modifications apportées à la législation sur la protection des données, en particulier l'introduction du RGPD, peuvent considérablement modifier le moment où les données doivent être supprimées. Vous devez peser le solde de ne pas supprimer les données qui pourraient être utiles (ou, en fait, requises par la loi) à des fins d'audit à une date ultérieure par rapport au besoin de respecter les droits des peuples (à la fois de manière générale et comme spécifiquement définis dans la législation pertinente) lorsque vous envisagez vos dessins. Cela peut être un problème avec les tables temporelles versionnées du système, car vous ne pouvez pas modifier l'historique pour purger des données personnelles sans modifications du schéma à court terme pour désactiver le suivi de l'historique pendant que vous apportez des modifications.
la source
Avec une colonne booléenne supprimée, vous commencerez à avoir des problèmes si votre table commence à grossir et à devenir vraiment grosse. Je vous suggère de déplacer les colonnes supprimées une fois par semaine (plus ou moins en fonction de vos spécifications) dans une autre table. De cette façon, vous avez une belle petite table active et une grande qui contient tous les enregistrements rassemblés au fil du temps.
la source
J'irais avec la table séparée. Ruby on Rails a un
acts_as_versioned
plugin, qui enregistre fondamentalement une ligne dans une autre table avec le suffixe_version
avant de le mettre à jour. Bien que vous n'ayez pas besoin de ce comportement exact, cela devrait également fonctionner pour votre cas (copie avant suppression).Comme @Spredzy, je vous recommanderais également d'ajouter une
delete_date
colonne pour pouvoir purger par programmation les enregistrements qui n'ont pas été restaurés après X heures / jours / peu importe.la source
La solution que nous utilisons en interne dans ce domaine consiste à créer une colonne d’état avec certaines valeurs codées en dur pour certains états spécifiques de l’objet: Supprimé, Actif, Inactif, Ouvert, Fermé, Bloqué - chaque statut ayant une signification utilisée dans l’application. Du point de vue de la base de données, nous ne supprimons pas les objets, nous modifions simplement le statut et conservons l'historique pour chaque modification de la table d'objets.
la source
Lorsque vous dites que "cette dernière solution nécessiterait une logique d'application supplémentaire pour ignorer les enregistrements" supprimés "", la solution simple consiste à disposer d'une vue qui les filtre.
la source
Comme ce que Spredzy a suggéré, nous utilisons un champ d’horodatage pour la suppression dans toutes nos applications. La valeur booléenne est superflue, car l'horodatage en cours de réglage indique que l'enregistrement a été supprimé. De cette façon, notre PDO ajoute toujours
AND (deleted IS NULL OR deleted = 0)
aux instructions select, à moins que le modèle demande explicitement que les enregistrements supprimés soient inclus.Actuellement, nous ne collectons pas les ordures sur toutes les tables, sauf celles contenant des blobs ou des textes l'espace est trivial si les enregistrements sont bien normalisés et l'indexation du
deleted
champ a un impact limité sur la vitesse de sélection.la source
Vous pouvez également placer la charge sur les utilisateurs (et les développeurs) et choisir une séquence de type "Êtes-vous sûr?", "Êtes-vous vraiment sûr?" et 'Êtes-vous absolument certain?' les questions avant l'enregistrement sont supprimées. Légèrement facétieux mais à considérer.
la source
J'ai l'habitude de voir des rangées de tableaux avec des colonnes du type 'DeletedDate' et je ne les aime pas. La notion même de «supprimé» est que l'entrée n'aurait pas dû être faite en premier lieu. Pratiquement, ils ne peuvent pas être supprimés de la base de données mais je ne les veux pas avec mes données chaudes. Les lignes logiquement supprimées sont, par définition, des données froides sauf si quelqu'un veut spécifiquement voir les données supprimées.
De plus, chaque requête écrite doit les exclure spécifiquement et les index doivent également les prendre en compte.
Ce que j'aimerais voir, c'est un changement au niveau de l'architecture de la base de données et de l'application: créer un schéma appelé "supprimé". Chaque table définie par l'utilisateur a un équivalent identique dans le schéma "supprimé" avec un champ supplémentaire contenant des métadonnées - l'utilisateur qui l'a supprimée et quand. Les clés étrangères doivent être créées.
Ensuite, les suppressions deviennent des insert-deletes. Tout d'abord, la ligne à supprimer est insérée dans son équivalent de schéma «supprimé». La ligne en question dans la table principale peut alors être supprimée. Il faut cependant ajouter une logique supplémentaire quelque part sur la ligne. Les violations de clé étrangère peuvent être traitées.
Les clés étrangères doivent être manipulées correctement. Il est déconseillé de supprimer logiquement une ligne mais dont les colonnes primaire / unique ont des colonnes dans d’autres tables qui y font référence. Cela ne devrait pas arriver de toute façon. Un travail standard peut supprimer des lignes veuve (lignes dont les clés primaires ne sont référencées dans aucune autre table malgré la présence d'une clé étrangère. Il s'agit toutefois d'une logique métier.
L'avantage général est la réduction des métadonnées dans le tableau et l'amélioration des performances qu'il apporte. La colonne 'deleteDate' indique que cette ligne ne devrait pas être réellement présente mais, pour des raisons pratiques, nous la laissons là et laissons la requête SQL la gérer. Si une copie de la ligne supprimée est conservée dans un schéma "supprimé", la table principale contenant les données hot contient un pourcentage plus élevé de données hot (en supposant qu'elles soient archivées à temps) et moins de colonnes de métadonnées inutiles. Les index et les requêtes n'ont plus besoin de prendre en compte ce champ. Plus la taille des lignes est courte, plus le nombre de lignes pouvant être insérées sur une page est élevé, plus SQL Server peut fonctionner rapidement.
Le principal inconvénient est la taille de l'opération. Il y a maintenant deux opérations au lieu d'une, ainsi que la logique supplémentaire et le traitement des erreurs. Cela peut entraîner plus de verrous que la mise à jour d'une seule colonne prendrait autrement. La transaction maintient les verrous sur la table plus longtemps et deux tables sont impliquées. La suppression des données de production, du moins selon mon expérience, est chose rare. Même dans l'une des tables principales, 7,5% des presque 100 millions d'entrées ont une entrée dans la colonne 'DeletedDate'.
En réponse à la question, l'application devrait être consciente de la «suppression complète». Il suffirait simplement de faire la même chose dans l'ordre inverse: insérez la ligne du schéma "supprimé" dans la table principale, puis supprimez la ligne du "schéma supprimé". Encore une fois, une logique et une gestion des erreurs supplémentaires sont nécessaires pour éviter les erreurs, les problèmes de clés étrangères, etc.
la source