J'ai une table très simple students
, structure comme ci-dessous, où la clé primaire est id
. Cette table est un stand-in pour environ 20 tables de plusieurs millions de lignes qui se réunissent beaucoup.Maintien de la cohérence logique avec une suppression en douceur, tout en conservant les informations d'origine
+----+----------+------------+ | id | name | dob | +----+----------+------------+ | 1 | Alice | 01/12/1989 | | 2 | Bob | 04/06/1990 | | 3 | Cuthbert | 23/01/1988 | +----+----------+------------+
Si Bob veut changer sa date de naissance, alors j'ai quelques options:
Mise à jour
students
avec la nouvelle date de naissance.Positifs: 1 Opération DML; la table est toujours accessible par une seule recherche de clé primaire.
Négatifs: je perds le fait que Bob n'a jamais pensé qu'il est né le 04/06/1990
Ajouter une colonne,
created date default sysdate
, à la table et changer la clé primaire àid, created
. Chaqueupdate
devient:insert into students(id, name, dob) values (:id, :name, :new_dob)
Ensuite, chaque fois que je veux informations les plus récentes procédez comme suit (Oracle, mais la question est synonyme de tous les SGBDR):
select id, name, dob from (select a.*, rank() over (partition by id order by created desc) as "rank" from students a) where "rank" = 1
Positifs: Je ne perdre aucune information .
Négatifs: Toutes les requêtes sur l'ensemble de la base de données prennent un peu plus de temps. Si la taille de la table est indiquée, cela n'a pas d'importance, mais une fois que vous êtes sur votre 5e
left outer join
, l'utilisation des balayages de plage plutôt que des balayages uniques commence à avoir un effet. Ajouter une autre colonne,deleted date default to_date('2100/01/01','yyyy/mm/dd')
, ou quoi que ce soit trop tôt, ou futuriste, date à mon goût. Changer la clé primaire àid, deleted
puis tous lesupdate
devient:update students x set deleted = sysdate where id = :id and deleted = (select max(deleted) from students where id = x.id); insert into students(id, name, dob) values (:id, :name, :new_dob);
et la requête pour obtenir les informations en cours devient:
select id, name, dob from (select a.*, rank() over (partition by id order by deleted desc) as "rank" from students a) where "rank" = 1
Positifs: Je ne perds jamais aucune information.
Négatifs: Deux opérations DML; Je dois toujours utiliser des requêtes classées avec le coût supplémentaire ou une analyse de plage plutôt qu'une analyse d'index unique dans chaque requête.
Créer une deuxième table, disent
student_archive
et change chaque jour en:insert into student_archive select * from students where id = :id; update students set dob = :newdob where id = :id;
Positifs: Ne jamais perdre aucune information.
Négatifs: 2 Opérations DML; Si jamais vous voulez obtenir toutes les informations, vous devez utiliser
union
ou unleft outer join
supplémentaire.Pour être complet, ont une structure de données horriblement de-normalisée:
id, name1, dob, name2, dob2...
etc.
Si le numéro 1 est pas une option si je ne veux jamais perdre de l'information et toujours faire une douce suppression. Le numéro 5 peut être écarté en toute sécurité en causant plus de problèmes que cela en vaut la peine. Je suis à gauche avec les options 2, 3 et 4 avec leurs aspects négatifs. Habituellement, je finis par utiliser l'option 2 et l'horrible 150 lignes (bien espacées) plusieurs sous-sélections qui vont avec.
tl; dr je me rends compte que je suis patiner près de la ligne sur un « non constructif » vote ici, mais:
Quelle est la méthode optimale (singulier!) Du maintien logique la cohérence alors jamais la suppression des données?
Y at-il un moyen plus efficace que ceux que j'ai documentés? Dans ce contexte, je définirai efficace comme "moins d'opérations DML" et/ou "pouvant supprimer les sous-requêtes". Si vous pouvez penser à une meilleure définition quand (si) répondez s'il vous plaît n'hésitez pas.
Merci! J'ai changé # 4 en 'insert ... update'; évidemment n'a pas assez réfléchi à ce sujet. – Ben