Le scénario est que j'ai un ensemble croissant d'utilisateurs, et au fil du temps, les utilisateurs annuleront leurs comptes que nous marquons actuellement comme «supprimés» (avec un indicateur) dans le même tableau.
Si les utilisateurs avec la même adresse e-mail (c'est ainsi que les utilisateurs se connectent) souhaitent créer un nouveau compte, ils peuvent se réinscrire, mais un NOUVEAU compte est créé. (Nous avons des identifiants uniques pour chaque compte, donc les adresses e-mail peuvent être dupliquées parmi celles en direct et supprimées).
Ce que j'ai remarqué, c'est que dans tout notre système, dans le cours normal des choses, nous interrogeons constamment la table des utilisateurs en vérifiant que l'utilisateur n'est pas supprimé, alors que je pense que nous n'avons pas du tout besoin de le faire ... ! [Clarification1: en 'interrogeant constamment', je voulais dire que nous avons des requêtes qui sont comme: '... DEPUIS les utilisateurs OERE isdeleted = "0" ET ...'. Par exemple, nous pouvons avoir besoin de récupérer tous les utilisateurs enregistrés pour toutes les réunions à une date particulière, donc dans CETTE requête, nous avons également des utilisateurs FROM OERE isdeleted = "0" - cela clarifie-t-il mon point?]
(1) continue keeping deleted users in the 'main' users table
(2) keep deleted users in a separate table (mostly required for historical
book-keeping)
Quels sont les avantages et les inconvénients de l'une ou l'autre approche?
la source
Réponses:
Vous pouvez par exemple utiliser un déclencheur pour déplacer automatiquement les utilisateurs supprimés vers la table d'historique.
la source
Je recommande fortement d'utiliser le même tableau. La raison principale est l'intégrité des données. Il y aura très probablement de nombreuses tables avec des relations en fonction des utilisateurs. Lorsqu'un utilisateur est supprimé, vous ne souhaitez pas laisser ces enregistrements orphelins.
La possession d'enregistrements orphelins rend à la fois plus difficile l'application des contraintes et rend plus difficile la recherche d'informations historiques. L'autre comportement à considérer si lorsqu'un utilisateur fournit un e-mail utilisé si vous souhaitez qu'il récupère tous ses anciens enregistrements. Cela fonctionnerait automatiquement en utilisant la suppression logicielle. En ce qui concerne le codage, par exemple dans mon application c # linq actuelle, la clause where supprimé = 0 est automatiquement ajoutée à la fin de toutes les requêtes
la source
Cela me donne une mauvaise odeur de design. Vous devriez cacher une telle logique. Par exemple, vous devriez avoir une
UserService
méthodeisValidUser(userId)
à utiliser pour "l'ensemble de votre système", au lieu de faire quelque chose comme:Votre façon de stocker l'utilisateur supprimé ne devrait pas affecter la logique métier.
Avec un tel type d'encapsulation, l'argument ci-dessus ne devrait plus affecter l'approche de votre persistance. Ensuite, vous pouvez vous concentrer davantage sur les avantages et les inconvénients liés à la persistance elle-même.
Les choses à considérer incluent:
Normalement, je prendrais une voie combinée:
la source
Afin de répondre correctement à cette question, vous devez d'abord décider: Que signifie «supprimer» dans le contexte de ce système / application?
Pour répondre à cette question, vous devez répondre à une autre question: pourquoi les enregistrements sont-ils supprimés?
Il existe plusieurs bonnes raisons pour lesquelles un utilisateur peut avoir besoin de supprimer des données. Habituellement, je trouve qu'il y a exactement une raison (par table) pour laquelle une suppression peut être nécessaire. Quelques exemples sont:
Il existe également de très mauvaises raisons pour la suppression définitive (plus d'informations sur ces raisons plus tard):
Pourquoi, demandez-vous, est-ce vraiment un gros problème? Quel est le problème avec un bon vieux
DELETE
?Donc, la suppression logicielle est meilleure, non? Non, pas vraiment:
La vérité est que ces deux approches sont fausses. La suppression est incorrecte. Si vous posez réellement cette question, cela signifie que vous modélisez l'état actuel au lieu des transactions. C'est une mauvaise, mauvaise pratique dans le domaine des bases de données.
Udi Dahan a écrit à ce sujet dans Don't Delete - Just Don't . Il y a toujours une sorte de tâche, opération, activité , ou (mon terme préféré) événement qui représente en fait la « suppression ». C'est OK si vous souhaitez par la suite dénormaliser dans une table "état actuel" pour les performances, mais faites-le après avoir cloué le modèle transactionnel, pas avant.
Dans ce cas, vous avez des "utilisateurs". Les utilisateurs sont essentiellement des clients. Les clients ont une relation commerciale avec vous. Cette relation ne disparaît pas simplement dans l'air, car ils ont annulé leur compte. Ce qui se passe vraiment, c'est:
Dans tous les cas, c'est le même client , et éventuellement le même compte (ie chaque renouvellement de compte est un nouvel accord de service). Alors pourquoi supprimez-vous des lignes? C'est très facile à modéliser:
C'est ça. C'est tout ce qu'on peut en dire. Vous n'avez jamais besoin de supprimer quoi que ce soit. Ce qui précède est une conception assez courante qui permet un bon degré de flexibilité mais vous pouvez le simplifier un peu; vous pouvez décider que vous n'avez pas besoin du niveau "Accord" et que "Compte" doit simplement aller dans un tableau "AccountStatus".
Si un besoin fréquent dans votre application est d'obtenir une liste des accords / comptes actifs , il s'agit d'une requête (légèrement) délicate, mais c'est à cela que servent les vues:
Et tu as fini. Maintenant, vous avez quelque chose avec tous les avantages des suppressions en douceur, mais aucun des inconvénients:
Le seul problème qui reste à résoudre est celui des performances. Dans de nombreux cas, il s'avère que ce n'est pas un problème en raison de l'index clusterisé
AgreementStatus (AgreementId, EffectiveDate)
- il y a très peu d'E / S cherchant à s'y produire . Mais s'il s'agit d'un problème, il existe des moyens de le résoudre, en utilisant des déclencheurs, des vues indexées / matérialisées, des événements au niveau de l'application, etc.Ne vous inquiétez pas trop tôt des performances - il est plus important de bien concevoir, et dans ce cas, «bien» signifie utiliser la base de données comme une base de données est censée être utilisée, en tant que système transactionnel .
la source
Je travaille actuellement avec un système où chaque table a un indicateur Supprimé pour la suppression logicielle. C'est le fléau de toute existence. Il brise totalement l'intégrité relationnelle lorsqu'un utilisateur peut "supprimer" un enregistrement d'une table, mais les enregistrements enfants qui FK vers cette table ne sont pas supprimés en cascade. Fait vraiment pour les données de poubelle après le temps.
Je recommande donc des tables d'historique distinctes.
la source
Briser la table en deux serait la chose la plus pâle imaginable.
Voici les deux étapes très simples que je recommanderais:
PS Désolé pour le retard de plusieurs mois dans la réponse!
la source
Si vous aviez récupéré des comptes supprimés lorsque quelqu'un revient avec la même adresse e-mail, j'aurais préféré garder tous les utilisateurs dans le même tableau. Cela rendrait le processus de récupération de compte trivial.
Cependant, lorsque vous créez de nouveaux comptes, il serait probablement plus simple de déplacer les comptes supprimés vers une table distincte. Le système en direct n'a pas besoin de ces informations, ne les exposez donc pas. Comme vous le dites, cela rend les requêtes plus simples et peut-être plus rapides sur des ensembles de données plus volumineux. Un code plus simple est également plus facile à gérer.
la source
Vous ne mentionnez pas le SGBD utilisé. Si vous avez Oracle avec la licence appropriée, vous pouvez envisager de partitionner la table des utilisateurs en deux partitions: les utilisateurs actifs et supprimés.
la source