2012-05-01 3 views
2

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:

  1. 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

  2. Ajouter une colonne, created date default sysdate, à la table et changer la clé primaire à id, created. Chaque update 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 les update 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.

  3. 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 un left outer join supplémentaire.

  4. 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.

Répondre

1

Je voudrais coller à # 4 avec quelques modifications. Pas besoin de supprimer des données de la table d'origine; il suffit de copier les anciennes valeurs pour archiver la table avant de mettre à jour (ou avant de supprimer) l'enregistrement original. Cela peut être facilement fait avec le déclencheur de niveau de ligne. Récupérer toutes les informations à mon avis n'est pas une opération fréquente, et je ne vois rien de mal avec un jointure/union supplémentaire. En outre, vous pouvez définir une vue, de sorte que toutes les requêtes seront simples du point de vue de l'utilisateur final.

+0

Merci! J'ai changé # 4 en 'insert ... update'; évidemment n'a pas assez réfléchi à ce sujet. – Ben

Questions connexes