Question

Je suis à la recherche dans la mise en œuvre-versionnage objet avec la torsion supplémentaire d'avoir besoin d'avoir les deux objets vivants et les projets, et pourrait utiliser les connaissances de quelqu'un d'expérience dans ce domaine, comme je commence à me demander s'il est même possible sans risquer hacks horribles.

Je vais le décomposer à des postes avec des balises pour le bien de l'exemple, mais mon cas d'utilisation est un peu plus général (impliquant dimensions changeant lentement - http://en.wikipedia.org/wiki/Slowly_changing_dimension ).

Supposons que vous avez une table de messages, une table de balises, et une table post2tag:

posts (
 id
)

tags (
 id
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id)
)

Je suis dans le besoin d'une ou deux choses:

  1. Être capable de montrer exactement comment un poste ressemblait à un datetime arbitraire, y compris pour les lignes supprimées.
  2. Gardez une trace de qui modifie ce, pour une piste de vérification complète.
  3. a besoin d'un ensemble de vues matérialisées (tableaux « live ») par souci de maintenir l'intégrité référentielle (à savoir l'exploitation forestière devrait être transparente pour les développeurs).
  4. doit être dûment rapide pour vivre et les derniers projets de lignes.
  5. Etre capable d'avoir un projet de coexiste poste avec un poste en direct.

Je l'ai étudié différentes options. Jusqu'à présent, le meilleur que je suis venu avec (sans point # 4 / # 5) ressemble un peu à la configuration type6 hybride SCD, mais au lieu d'avoir un booléen courant il y a une vue matérialisée pour la ligne actuelle. Pour toutes fins utiles, il ressemble à ceci:

posts (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by
)

post_revs (
 id,
 rev pkey,
 public,
 created_at,
 created_by,
 deleted_at
)

tags (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by
)


tag_revs (
 id,
 public,
 rev pkey,
 created_at,
 created_by,
 deleted_at
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id),
 public,
 created_at,
 updated_at,
 updated_by
)

post2tag_revs (
 post_id,
 tag_id,
 post_rev fkey post_revs(rev), -- the rev when the relation started
 tag_rev fkey tag_revs(rev), -- the rev when the relation started
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (post_rev, tag_rev)
)

J'utilise pg_temporal pour maintenir les indices sur la période (created_at, deleted_at). Et je garde les différentes tables de synchronisation en utilisant des déclencheurs. Yada yada yada ... Je crée les déclencheurs qui permettent d'annuler une modification de messages / balises de telle sorte que le projet est stocké dans les tours sans être publié. Il fonctionne très bien.

Sauf quand je besoin de vous soucier projet de rangée relations connexes sur post2tag. Dans ce cas, tous l'enfer se déchaîne, et ce conseils pour moi que j'ai une sorte de problème de conception là-dedans. Mais je suis à court d'idées ...

Je l'ai considéré comme l'introduction de la duplication des données (à savoir les n lignes de post2tag introduites pour chaque projet de révision). Ce genre d'œuvres, mais a tendance à être beaucoup plus lent que ce que je voudrais que ce soit.

Je l'ai considéré comme l'introduction de tableaux de projets pour le « dernier projet », mais cela tend rapidement à devenir très très laid.

Je l'ai considéré toutes sortes de drapeaux ...

Alors question: est-il un moyen généralement accepté de gérer en direct vs lignes non en direct dans un environnement contrôlé rangée version? Et sinon, qu'est-ce que vous avez essayé et ont été un succès raisonnable avec?

Était-ce utile?

La solution 4

Je pense que je cloué. Fondamentalement, vous ajoutez un champ de projet (unique) aux tableaux correspondants, et vous travaillez sur les courants d'air comme si elles étaient un nouveau poste / tag / etc:.

posts (
 id pkey,
 public,
 created_at stamptz,
 updated_at stamptz,
 updated_by int,
 draft int fkey posts (id) unique
)

post_revs (
 id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (id, created_at)
)

tags (
 id pkey,
 public,
 created_at,
 updated_at,
 updated_by,
 draft fkey tags (id) unique
)


tag_revs (
 id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (id, created_at)
)

post2tag (
 post_id fkey posts(id),
 tag_id fkey tags(id),
 public,
 created_at,
 updated_at,
 updated_by,
 pkey (post_id, tag_id)
)

post2tag_revs (
 post_id,
 tag_id,
 public,
 created_at,
 created_by,
 deleted_at,
 pkey (post_id, tag_id, created_at)
)

Autres conseils

Modélisation Anchor est un moyen agréable de mettre en œuvre un temporel dB - voir le article de Wikipedia aussi. Prend un certain temps pour s'y habituer, mais le travail agréable. Il y a un outil de modélisation en ligne et si vous chargez le fichier XML fourni [File -> Load Model from Local File] vous devriez voir quelque chose comme ça -. utiliser aussi [Layout --> Togle Names]

entrer image description ici

Le [Generate --> SQL Code] produira DDL pour les tables, vues et fonctions point en temps. Le code est assez long, donc je ne suis pas le poster ici. Vérifiez le hors code - vous devrez peut-être modifier pour votre DB.

Voici le fichier à charger dans l'outil de modélisation.

<schema>
<knot mnemonic="EXP" descriptor="Expired" identity="smallint" dataRange="char(1)">
<identity generator="true"/>
<layout x="713.96" y="511.22" fixed="true"/>
</knot>
<anchor mnemonic="US" descriptor="User" identity="int">
<identity generator="true"/>
<attribute mnemonic="USN" descriptor="UserName" dataRange="varchar(32)">
<layout x="923.38" y="206.54" fixed="true"/>
</attribute>
<layout x="891.00" y="242.00" fixed="true"/>
</anchor>
<anchor mnemonic="PO" descriptor="Post" identity="int">
<identity generator="true"/>
<attribute mnemonic="TIT" descriptor="Title" dataRange="varchar(2)">
<layout x="828.00" y="562.00" fixed="true"/>
</attribute>
<layout x="855.00" y="471.00" fixed="true"/>
</anchor>
<anchor mnemonic="TG" descriptor="Tag" identity="int">
<identity generator="true"/>
<attribute mnemonic="TGT" descriptor="TagText" dataRange="varchar(32)">
<layout x="551.26" y="331.69" fixed="true"/>
</attribute>
<layout x="637.29" y="263.43" fixed="true"/>
</anchor>
<anchor mnemonic="BO" descriptor="Body" identity="int">
<identity generator="true"/>
<attribute mnemonic="BOT" descriptor="BodyText" dataRange="varchar(max)">
<layout x="1161.00" y="491.00" fixed="true"/>
</attribute>
<layout x="1052.00" y="465.00" fixed="true"/>
</anchor>
<tie timeRange="datetime">
<anchorRole role="IsTagged" type="PO" identifier="true"/>
<anchorRole role="IsAttached" type="TG" identifier="true"/>
<anchorRole role="BYAuthor" type="US" identifier="false"/>
<knotRole role="Until" type="EXP" identifier="false"/>
<layout x="722.00" y="397.00" fixed="true"/>
</tie>
<tie timeRange="datetime">
<anchorRole role="Contains" type="PO" identifier="true"/>
<anchorRole role="ContainedIn" type="BO" identifier="false"/>
<layout x="975.00" y="576.00" fixed="true"/>
</tie>
<tie>
<anchorRole role="CreatedBy" type="TG" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="755.10" y="195.17" fixed="true"/>
</tie>
<tie>
<anchorRole role="CreatedBy" type="PO" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="890.69" y="369.09" fixed="true"/>
</tie>
<tie>
<anchorRole role="ModifiedBy" type="BO" identifier="true"/>
<anchorRole role="Author" type="US" identifier="false"/>
<layout x="1061.81" y="322.34" fixed="true"/>
</tie>
</schema>

Je l'ai mis en place une base de données temporelle en utilisant le type de 2 et PostgreSQL SCD Règles et triggers et enveloppé dans un paquet autonome pour ActiveRecord: http://github.com/ifad/chronomodel

La conception est indépendante de la langue / cadre, bien que - vous pouvez créer des règles et des déclencheurs manuellement et la base de données se chargera du reste. Jetez un oeil à https://github.com/ifad/chronomodel/blob/master /README.sql .

En outre l'indexation et l'interrogation efficace des données temporelles en utilisant des opérateurs géométriques est inclus comme un bonus. : -)

post2tag_revs a un problème en ce qu'elle tente d'exprimer 2 concepts fondamentalement différents.

Une étiquette appliquée à un projet de révision de poste ne jamais s'applique à cette révision particulière, à moins que la révision est jamais publiée.

Une fois une balise est publiée (par exemple associée à une révision après publication), il applique à chaque révision future du poste jusqu'à ce qu'il soit révoqué.

Et avec une révision associait publiée ou unasociating, est pas nécessairement en même temps avec une révision en cours de publication, sauf si vous forcez artificiellement ce clonage par une révision juste pour que vous pouvez associer des ajouts ou des suppressions d'étiquette ...

Je changer le modèle en faisant post2tag_revs.post_rev ne concerne que les projets de balises. Une fois que la révision est publiée (et l'étiquette est en direct), j'utiliser une colonne d'horodatage pour marquer le début et la fin de la validité publiée. Vous pouvez ou ne veulent pas une nouvelle entrée de post2tag_revs pour représenter ce changement.

Comme vous le soulignez, ce qui rend cette relation bi-temporelle . Vous pouvez améliorer les performances dans le cas « normal » en ajoutant une valeur booléenne à post2tag pour indiquer que la balise est actuellement associé au poste.

Utilisez uniquement 3 tables:., Tags et messages post2tag

colonnes Ajouter des start_time et END_TIME à toutes les tables. Ajouter un index unique pour la clé, start_time et end_time. Ajouter un index unique pour clé où end_time est nulle. Ajouter trigers.

Pour le courant:

SELECT ... WHERE end_time IS NULL

A l'heure:

WHERE (SELECT CASE WHEN end_time IS NULL
THEN (start_time <= at_time)
ELSE (start_time <= at_time AND end_time > at_time)
END)

Rechercher des données actuelles ne tarde pas à cause de l'indice fonctionnel.

Edit:

CREATE UNIQUE INDEX ... ON post2tag (post_id, tag_id) WHERE end_time IS NULL;
CREATE UNIQUE INDEX ... ON post2tag (post_id, tag_id, start_time, end_time);

FOREIGN KEY (post_id, start_time, end_time) REFERENCES posts (post_id, start_time, end_time) ON DELETE CASCADE ON UPDATE CASCADE;
FOREIGN KEY (tag_id, start_time, end_time) REFERENCES tags (tag_id, start_time, end_time) ON DELETE CASCADE ON UPDATE CASCADE;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top