Est-ce une mauvaise pratique d'avoir une colonne «statut d'enregistrement» dans une table de base de données?


12

Je dois d'abord préciser que la colonne d'état n'est pas destinée à refléter l'état d'un élément réel représenté par l'enregistrement (ligne) dans le tableau. Il vise plutôt à montrer l'état de l'enregistrement lui-même.

Il peut être aussi simple que actif / inactif ou compliqué comme approuvé / supprimé / Verrouillé / En attente / Rejeté, etc. L'état peut être stocké sur un booléen / courte colonne entière ou une colonne d'un seul caractère, avec correspondances comme true/ 1= active ou A= Approuvé.

L'idée de base est d'avoir un support de récupération de type corbeille / corbeille dans l'application (et de le simuler dans la base de données). S'il existe une interface graphique frontale ou une autre interface qui peut soi-disant permettre à un utilisateur de "supprimer" des enregistrements, il ne supprime pas réellement l'enregistrement dans la table, mais modifie simplement l'état de l'enregistrement en Inactif ou Supprimé. Lorsque l'interface récupère des enregistrements, elle obtient toujours les enregistrements qui correspondent uniquement à la condition selon laquelle l'état est Actif ou Approuvé.

Si l'utilisateur fait une erreur et que l'enregistrement "supprimé" (du point de vue de l'utilisateur) doit être récupéré, un administrateur de base de données peut facilement corriger l'enregistrement en étant actif ou approuvé, ce qui serait mieux que de rechercher des sauvegardes et, espérons-le, de trouver l'enregistrement d'origine Là. Ou l'interface elle-même peut permettre à l'utilisateur d'afficher les enregistrements supprimés dans une vue distincte, et de les restaurer selon les besoins, ou même de les supprimer définitivement (suppression de l'enregistrement réel).

Mes questions:

  • Est-ce une bonne ou une mauvaise pratique?
  • Cela affecte-t-il la normalisation des données?
  • Quels sont les pièges potentiels?
  • Existe-t-il une autre méthode pour atteindre le même objectif? (voir la note)
  • Comment pouvez-vous faire en sorte que la base de données applique des contraintes uniques sur les données pour un certain statut uniquement (mais autorise un nombre illimité de doublons pour d'autres statuts)?
  • Pourquoi les bases de données ne fournissent-elles pas une fonctionnalité de type «corbeille» ou un suivi / récupération de table en mode natif, afin que nous puissions laisser les interfaces supprimer les enregistrements réels sans souci?

Remarque: J'ai lu sur la gestion d'une table d'historique distincte, mais cela semble pire en termes de stockage et d'avoir à générer des déclencheurs et à maintenir les déclencheurs à jour avec le schéma de la table suivie.


Le problème des contraintes uniques (que vous avez déjà nommées) est exactement la raison pour laquelle les tables d'historique sont souvent préférables - vous pouvez conserver les contraintes de clé uniques sur les tables d'origine et ne pas les ajouter sur la table d'historique. d'utiliser des options de stockage spécifiques (dépendant de la base de données) pour eux, donc ils sont souvent meilleurs en termes de stockage, pas pire. Lorsque vous avez beaucoup de ces tables, les déclencheurs et les tables d'historique ne doivent pas être écrits à la main, mais générés, cela résoudra le problème de la façon de les garder "à jour".
Doc Brown

Réponses:


5

Je le connais comme un "Soft Delete"; il suffit de marquer un enregistrement comme "supprimé", même s'il ne l'est pas vraiment.

Est-ce une bonne ou une mauvaise pratique?

Ça dépend.
Si c'est quelque chose dont vos utilisateurs ont besoin [beaucoup], c'est probablement une bonne chose. Dans la grande majorité des cas, cependant, je dirais que cela ajoute [beaucoup] de frais généraux pour peu d'avantages.

Cela affecte-t-il la normalisation des données?

Non, mais il aura une incidence sur votre indexation de ces données.
Assurez-vous d'inclure la colonne "supprimé" dans vos index, afin que ces lignes soient exclues le plus tôt possible dans vos requêtes.

Quels sont les pièges potentiels?

Vos données deviennent un peu plus complexes. Tout ce qui se rapproche des données doit "connaître" ces enregistrements supplémentaires, "pas vraiment là". Ou, vous devez créer des vues sur les tables qui excluent ces lignes et utiliser ces vues dans, disons, votre outil de création de rapports préféré.

Votre base de données peut augmenter en taille. Si vous ne supprimez pas vraiment ces lignes, elles sont toujours là, occupant de l'espace. Cela peut ou non être un problème, d'autant plus que vous les avez inclus dans vos index, donc l'espace qu'ils consomment est multiplié.

Existe-t-il une autre méthode pour atteindre le même objectif? (voir la note)

Non, pas vraiment.

Comment pouvez-vous faire en sorte que la base de données applique des contraintes uniques sur les données pour un certain statut uniquement (mais autorise un nombre illimité de doublons pour d'autres statuts)?

Pas facilement. L'intégrité référentielle déclarative (clauses de clé étrangère) est le moyen le plus propre de l'implémenter et il est facile pour des choses comme les outils de création de rapports de reprendre ces règles pour déterminer les relations entre les tables. Ces règles s'appliquent à tous les enregistrements, quel que soit leur "statut" (et il n'y a aucun moyen de contourner cela).

L'alternative consiste à utiliser des déclencheurs, des extraits de code procédural qui renforcent l'intégrité référentielle entre les tables et effectuent toutes les tâches intelligentes et conditionnelles dont vous avez besoin. C'est bon pour votre cas particulier, mais la plupart des avantages de Declarative RI sortent de la fenêtre - il n'y a pas de relations [externes] détectables entre vos tables; c'est tout "caché" dans les déclencheurs.

Pourquoi les bases de données ne fournissent-elles pas une fonctionnalité de type «corbeille» ou un suivi / récupération de table en mode natif, afin que nous puissions laisser les interfaces supprimer les enregistrements réels sans souci?

Pourquoi le feraient- ils?

Ce sont des bases de données, après tout, pas des systèmes de fichiers ou des feuilles de calcul.

Ce qu'ils font, ils [peuvent] le faire très, très bien.

Ce qu'ils ne font pas, il n'y a probablement pas eu beaucoup de demande.


Bonne réponse, mais il existe des options alternatives, par exemple déplacer les lignes dans une table de sauvegarde d'où vous pouvez les récupérer. La table de sauvegarde peut avoir des indices minimaux. Cela minimise les problèmes que vous notez avec l'approche existante (index plus grand, confusion potentielle pour les utilisateurs de la table, etc.), mais ajoute évidemment le fait que vous avez une autre table à gérer (et signifie que les entrées ont disparu par rapport aux références de clés étrangères). Il existe de nombreuses autres options - mais en effet celles qui viennent à l'esprit sont toutes des implémentations personnalisées, pas quelque chose de général fourni par chaque base de données SQL pour de tels cas.
Frank Hopkins

9

C'est une pratique. Que ce soit bon ou mauvais dépend fortement de votre application et de la fréquence à laquelle vous allez vraiment avoir besoin / vouloir faire une "suppression". Je serais assez douteux d'un plan pour mettre ce type de colonne de chaque table dans le système - il semble très peu probable que vous vous donniez vraiment la peine d'implémenter la suppression de suppression sur chaque table du système. Et cela nécessite une implémentation - dans la grande majorité des cas, vous ne supprimez pas une seule ligne d'une seule table, vous devez parcourir les tables enfants en supprimant les lignes et en mettant à jour les tables associées.

Pour la plupart des autres questions, cela dépend fortement de l'implémentation. Par exemple, Oracle fournit différentes méthodes pour suivre toutes les modifications apportées à une table - Flashback Data Archive (FDA également connu sous le nom de Total Recall) étant l'approche la plus récente pour maintenir un historique complet de chaque version d'une ligne et l'archivage dans la base de données pour la mise en œuvre le motif de suppression progressive. D'autres bases de données peuvent fournir d'autres moyens d'implémenter le modèle. En fonction de la base de données et de la façon dont vous implémentez la suppression logicielle, il y aura divers impacts sur les performances, si et comment les contraintes peuvent être appliquées, etc. Si nous parlons d'Oracle, vous pouvez faire beaucoup avec les index basés sur les fonctions, par exemple , dans SQL Server, vous pouvez souvent utiliser des index filtrés à des fins similaires.


Oracle Flashback est exactement la solution idéale pour ce que je veux. Dommage que ce soit la propriété d'Oracle.
ADTC

4

Il est très courant d'utiliser un champ "marqué pour suppression" dans les systèmes MRP / ERP.

Par exemple, on peut vouloir marquer un enregistrement de pièce ou d'inventaire qui n'est plus vendu comme inactif, mais il y a encore des commandes en cours qui lui sont associées. Effectuer une véritable suppression de l'enregistrement peut affecter les commandes qui n'ont pas encore été expédiées, les entrées de grand livre qui n'ont pas encore été enregistrées, les tables d'historique qui ne seront pas construites avant la fin du mois, etc. De nombreux systèmes interdiront la suppression d'un enregistrement à moins qu'il ne passe une série de validations par rapport à d'autres tables. Si vous supprimez en cascade vos relations, une véritable suppression peut être encore plus destructrice.

Au lieu de cela, en le marquant pour suppression, vous placez un marqueur d'intention clair sur l'enregistrement et, plus tard, une tâche planifiée peut supprimer l'enregistrement s'il vérifie que toutes les tables associées ne le référencent plus.

Un cas similaire pourrait être fait pour cette fonctionnalité sur une table client et d'autres tables "à long terme". Cela a même du sens sur des tables plus volatiles comme les commandes, bien que le nom du drapeau puisse devenir quelque chose comme "expédié" ou "annulé". Il remplit la même fonction: ne le supprimez pas cette seconde, mais utilisez-le comme indicateur pour le programme de purge afin qu'il tente de valider la suppression de l'enregistrement à l'avenir.


3

Comme solution alternative, l'utilisation du sourcing d'événements permet des objectifs similaires sans compliquer la structure de la table, bien que cela rend le code de modification de vos données un peu plus complexe, car vous devez écrire la modification dans un événement qui peut être conservé dans l'historique des événements. . Cela vous permet ensuite de recréer la base de données telle qu'elle était à un moment donné, ce qui peut être une fonctionnalité très utile.

(Je ne crois pas que ce soit ce que vous vouliez dire par "table d'historique", ce que je pense que vous vouliez simplement copier les enregistrements modifiés ou supprimés dans une autre table avant de les changer)


Concept intéressant. Je vais voir comment cela peut être mis en œuvre.
ADTC

1

Je vois et utilise fréquemment ce modèle pour ces cas d'utilisation:

  • des métadonnées où vous souhaitez uniquement afficher les valeurs en vigueur aujourd'hui. Par exemple, pour choisir dans une liste de constructeurs automobiles dans une liste déroulante où enabled = 1 les valeurs des tableaux pour ID, VALUE, ENABLED sont 1, 'Ford', 1 et 2, 'Edsel', 0, 3, 'Toyota' , 1 ne donne que les choix de Ford et Toyota
  • pour un système de gestion de cas où le paradigme est qu'un cas ne peut être que dans un état à la fois. Dans ce cas, la colonne à bascule était appelée CURRENT avec des valeurs de 0 ou 1 appliquées par des contraintes de vérification. Lorsqu'un cas passe d'un état à un autre, l'application met à jour l'indicateur CURRENT de l'ancien état à 0 et le nouveau à 1.

Le problème consiste à appliquer l'intégrité des données si plusieurs applications ou services Web écrivent dans des tables. Comment vous assurez-vous que pour un cas il n'y a qu'un seul état actuel? Comme le souligne Justin Cave, cela peut être fait dans Oracle en créant un index virtuel basé sur une fonction, mais cette surcharge supplémentaire pour ce qui semblait à l'origine un concept simple.


1

C'est une bonne pratique si vous prévoyez d'utiliser vos données pour la génération de rapports (toute application suffisamment grande devrait avoir des rapports).

Afin d'accélérer votre application, vous ne devez vraiment pas laisser les outils de reporting s'exécuter sur votre base de données. En tant que tel, vous devez effectuer une copie / synchronisation vers une autre base de données.

J'utilise recordStatusseulement deux états ACTIVEou CANCELLEDen combinaison avec un lastUpdatedOnhorodatage. J'utilise recordStatusplutôt que statusce qui a généralement un sens commercial.

Lorsque je synchronise la base de données de génération de rapports avec l'application, je filtre les informations lastUpdatedOnpour savoir lesquelles je vais remplacer du côté des rapports.

En ce qui concerne les rapports, je n'aurai pas les champs recordStatusou lastUpdatedOncar ils ne seront généralement pas signalés. En tant que tel, lorsque je vois un CANCELLEDstatut, je supprimerais l'enregistrement du côté du rapport de cette façon, il n'a que des enregistrements actifs.

Cela peut être étendu à d'autres types de magasins tels que les archives ou les sauvegardes où une synchronisation presque complète est requise. Cependant, la notification est l'objectif le plus courant.

Notez votre exemple Approved, New, Pendingn'est pas une bonne idée de mettre un champ commun comme qui a une entreprise qui signifie qu'il devrait aller que là où il fait des affaires de sens sage.

Quant à verrouillé, utilisez versionNoce qui fournit un verrou optimiste pour votre dossier.

Une autre option au lieu de recordStatusest de recordActivele stocker comme un booleanqui prend moins d'espace et moins d'indexation, mais je serais préoccupé par les besoins futurs que vous ne pouvez pas prévoir.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.