eltigree: Bitemporale Datenhalten (Datenhistorisierung)

Hallo zusammen!
Ich möchte gerne meine Daten (MS SQL Server 2005) bitemporal halten, d.h. eine Datenhistorisierung einfügen und bräuchte hierzu noch Tipps.

Ich habe bereits gelesen, dass es von Vorteil ist, die Historisierung und die Stammdaten getrennt zu führen. Nun habe ich aber das Problem, dass ich nicht genau weiss wie ich diese Daten führen muss.

Meine Historisierungsidee ist, dass ich Mutationen in die Vergangenheit sowohl auch in die Zukunft vornehmen kann. Die History-Tabelle legen ich analog der Original-Tabelle an und ergänze diese mit 4 zusätzlichen Spalten ExistsFrom (Kenntnis-Ab des Datensatzes), ExistsTo (Kenntnis-Bis des Datensatzes, bleibt immer leer), ValidFrom (Gültig-Ab des Datensatzes) und ValidTo (Gültig-Bis des Datensatzen). Nun bevor ja der aktuelle Datensatz mit Insert oder Update mutiert wird, muss ich diesen ja in die History-Tabelle verschieben und mit dem ValidTo auf das aktuelle Datum setzen. Erst dann schreibe ich die Änderung wieder in die Original-Tabelle. Was passiert aber, wenn ich eine Mutation in die Zukunft mache, somit wird es ja schwierig für die Datenhaltung? Welchen Record muss ich in der Original-Tabelle beibehalten -> die letzte Mutation oder den gültigen Record (wie kann ich diesen ermitteln)? Das ganze zeigt sich ja sehr schwierig, was die SQL-Querys angeht... Ich möchte diese Historisierugn in meine JAVA API JPA einbinden. Habe hier einen Knüppel in der Leitung. Wäre für jede Hilfe sehr dankbar.

mfg eltigree

-> ExistsFrom
-> ExistsTo
-> ValidFrom
-> ValidTo

  1. Hello,

    4 zusätzlichen Spalten ExistsFrom (Kenntnis-Ab des Datensatzes), ExistsTo (Kenntnis-Bis des Datensatzes, bleibt immer leer), ValidFrom (Gültig-Ab des Datensatzes) und ValidTo (Gültig-Bis des Datensatzen).

    ich lese deine Erklärung, aber mir ist noch nicht ganz klar wozu du sie benötigst.

    • Wenn dein Datensatz ein inhaltliches gültigAb/bis hat, dann sollte er dies auch in der "Produktivtabelle" haben. In dem Fall reicht also das technisch gültigAb/bis, weil der Rest unverändert in die Historie übernommen wird
    • Wenn dein Datensatz kein inhaltliches gültigAb/bis hat, warum solltest du dann in der Historie eines eröffnen wollen? Wo ist der Unterschied.
      -> so wie ich es sehe (und wir es beim Kunden einsetzen) reicht ein zusätzliches Pärchen um den Gültigkeitsbereich des archivierten Satzes zu erfassen

    Nun bevor ja der aktuelle Datensatz mit Insert oder Update mutiert wird, muss ich diesen ja in die History-Tabelle verschieben und mit dem ValidTo auf das aktuelle Datum setzen.

    Zunächst mal kannst du die Antwort auf eine Fragen in Form von BEFORE INSERT/DELETE/UPDATE Triggern suchen. Mit diesen erhälst du Zugriff auf die relevanten Informationen und kannst die Sätze übertragen.
    Wir machen es tatsächlich so, dass die Historie einen 100% Spiegel des Produktivbestands darstellt, also auch den aktuellen Satz mit enthält. Wer sich das warum mal überlegt hat übersteigt gerade meine Kenntnis, es erleichtert aber zumindest mal die Auswertung: alle Daten sind garantiert an einer Stelle zu finden, gleichzeitig bleiben die Produktivtabellen schlank und enthalten nur die Daten, die wirklich inhaltlich gültig sind.

    Aber ja, man muss sich trotzdem der Tatsache bewusst sein, dass man sich die schlanken Produktivtabellen in Form von zusätzlichen Triggern erkauft.

    MfG
    Rouven

    --
    -------------------
    sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
    Death is nature's way of telling you to slow down.
    1. Hallo zusammen.

      Vielen Dank für die prompten Antworten.
      In der Konzeption der bitemporalen Datenhaltung wird explizit von 4 zusätzlichen Datumseinträgen gesprochen. Dies soll eine lückenlose Historisierung darstellen. Dadurch kann ja genau ermittelt werden, ab wann ein Datensatz existiert und was dieser für einen Gültigkeitsbereich hat.

      Ich muss meine API so anpassen, dass ich in meinen Daten über ein Datum "blättern" kann, so dass ich die Daten wirklich per Datum (vergangenheit und zukunft) abrufen kann. Ich habe nur mehrmals davon gelesen, dass man diese Daten trennen sollte, so dass in der haupttabelle jeweils der gültige Satz enthalten ist.
      Ich weiss nicht, ob es vielleicht andere Ansätze gibt...

      Das Before insert / update / delete kenne ich, aber ich weiss nicht wie ich das z.B. bei jpa lösen soll, da hier die daten über ein binding (toplink) gekoppelt sind...

      Zudem möchte ich eine Lösung anstreben, welche ich modular einsetzen kann, d.h. auch für weitere JAVA-APIs einsetzen kann.

      Vielen Dank für eure Tipps :-)

      1. Hello,

        In der Konzeption der bitemporalen Datenhaltung wird explizit von 4 zusätzlichen Datumseinträgen gesprochen. Dies soll eine lückenlose Historisierung darstellen. Dadurch kann ja genau ermittelt werden, ab wann ein Datensatz existiert und was dieser für einen Gültigkeitsbereich hat.

        leuchtet mir zwar irgendwie ein, aber wie gesagt, NUR wegen der Historisierung machen nur zwei der vier Zeitfelder aus meiner Sicht Sinn, die anderen beiden stellen auch für einen aktiven Satz gültige Informationen dar (siehe mein Beispiel).
        Aber am Ende des Tages ist das verwand mit der Diskussion "alles in einer Tabelle" vs. "Trennung Produktion-Archiv"

        Ich muss meine API so anpassen, dass ich in meinen Daten über ein Datum "blättern" kann, so dass ich die Daten wirklich per Datum (vergangenheit und zukunft) abrufen kann. Ich habe nur mehrmals davon gelesen, dass man diese Daten trennen sollte, so dass in der haupttabelle jeweils der gültige Satz enthalten ist.

        der Witz deiner 4 Felder ist, dass es nicht "den" gültigen Satz sondern "die" gültigen Sätze gibt - abhängig von deinem Betrachtungswinkel entweder "technisch" oder "fachlich"

        In Ergänzung zu meinem Beispiel, folgende Fragestellungen:
        (1) Nenne mir den Wohnort des Kunden für 2008!
        Antwort:
        01.01.-30.06. FFM
        01.07.-31.12. Berlin

        (2) Nenne mir den Wohnort des Kunden für 2008, so wie er mir am 05.01. bekannt war!
        01.01.-31.12. FFM

        (3) Nenne mir alle Wohnorte, so wie sie mir mal bekannt waren:
        siehe (1) + (2)

        Das Before insert / update / delete kenne ich, aber ich weiss nicht wie ich das z.B. bei jpa lösen soll, da hier die daten über ein binding (toplink) gekoppelt sind...

        korrigiere mich wenn ich falsch liege, aber das ist Java-Ebene. Bei den Triggern rede ich über die Datenbankebene. Der ist es dann egal, wer auf die zugreift, die Historienverwaltung macht die Datenbank. Machen wir hier genau so, die Anwendung läuft auf Entity-Beans, irgendwann persistiert der Application-Server und die Datenbank kümmert sich um die Verwaltung der Historie.

        MfG
        Rouven

        --
        -------------------
        sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
        "I wish it need not have happened in my time" - "So do I, and so do all who live to see such times. But that is not for them to decide. All we have to decide is what to do with the time that is given us."  --  J.R.R. Tolkien: "The Lord Of The Rings: The Fellowship Of The Ring"
      2. Hallihallo, es gibt sicherlich verschiedene Ansichten (und dann auch Implementierungen) zu dem Thema.

        Es kommt ganz darauf an ...

        • was benötigst du häufiger (welche Perspektive auf die Daten)
        • womit hast weniger Arbeit (was ist technisch einfacher zugewährleisten ist)
        • wie "real-time" oder entkoppelt muss/soll die Historisierung funktionieren

        Ciao, Frank

  2. Hello,

    das ist nicht ganz unspannend:

    du musst für jeden DMT die entsprechende Umkehrfunktion ermöglichen, also bei String-Veränderung also z.B. "streiche - setze an Position". Bei Multiplikation könnte man vermuten, dass es reicht, später wieder durch den Multiplikator (bei Wiki haißt der Multiplikand (?) ) zu dividieren. Aber was ist bei Multipklation mit 0?
    Und da wird uns auch schon das nächste Problem klar: die Genauigkeit und der zulässige Wertebereich.

    Viel Spaß

    und noch ein paar Stichworte:

    • Stammdaten
    • Bewegungsdaten
    • Aufsetzpunkte
    • Binärlog (muss man bei mySQL nur einschalten)

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
  3. Hallo eltigree,

    Ich möchte gerne meine Daten (MS SQL Server 2005) bitemporal halten, d.h. eine Datenhistorisierung einfügen und bräuchte hierzu noch Tipps.

    Ich habe erstmal nachgesehen was "biotemporal" in diesem Kontext heißt. Das meint wohl "Gültigkeitszeitraum und Erzeugungszeitpunkt eines Datensatzes werden gespeichert". Also eine bestimmte art der "Historisierung".

    Ich habe bereits gelesen, dass es von Vorteil ist, die Historisierung und die Stammdaten getrennt zu führen.

    Wo hast Du das gelesen und welche Argumente wurden dafür genannt?

    Von der "reinen Lehre des Datenbankentwurfs" her sehe ich nämlich kein Argument, das so zu tun. Du kannst einfach zusätzliche Spalten für den Gültigkeitstzeitraum und Erzeugungsdatum hinzufügen. Der "aktuelle" Datensatz ist eben der, der zum entsprechenden Zeitpunkt gültig ist. Die "aktuellen Daten" sind also nur eine Sicht (View) auf die Tabelle aller Daten.

    Nun kann es evtl Performancegründe geben, nur die aktuellen Datensätze in einer eigenen Tabelle zu halten. SQL-Server unterstützt anscheinend so genannte "Indexed Views" also Sichten auf Tabellen die in irgend einer Weise zwischengespeichert werden. Ich würde mich mal informieren, ob diese geeignet sind, das Problem zu lösen.

    Grüße

    Daniel

    1. Hello,

      Nun kann es evtl Performancegründe geben, nur die aktuellen Datensätze in einer eigenen Tabelle zu halten.

      das ist eine Möglichkeit. Eine weitere ist wirklich die undurchschaubare Datenlandschaft. Du musst ja beachten, dass du eine fachliche und eine technische Gültigkeit eines Satzes hast. Die selbe fachliche Gültigkeit kann zu verschiedenen Zeitpunkten von anderen Werte belegt sein.
      Bsp.:
      am 01.01. teilst du deiner Bank mit, dass du im letzten Jahr in Frankfurt gelebt hast (01.01.-31.12.)
      am 30.01. teilst du deiner Bank mit, dass du dich geirrt hast, und nur vom 01.01.-30.06. in Frankfurt, vom 1.07.-31.12. aber in Berlin gelebt hast.

      Je nach Historiesierungskonzept hast du nun 3 bis 4 Einträge in deiner Tabelle, die dir diesen Sachverhalt abbilden.
      Von der Lesbarkeit und Performance kann es einen Unterschied machen, wenn du dich im Alltag nur für "wirklich gültige" Sätze interessierst und nur von Zeit zu Zeit mal im Archiv kramen möchtest.

      MfG
      Rouven

      --
      -------------------
      sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
      Friendships are a lot like a backyard garden. We plan to tend to them, but we just always seem to put it off until next week. --  Christian Clemenson as Jerry Espenson in Boston Legal: "Patriot Acts"
      1. Hallo Rouven,

        Ja bei solchen Dingen wird das Datenmodell natürlich etwas komplexer. Dennoch denke ich, dass man auch hier erstmal anstreben sollte, ein sauberes Datenmodell zu entwerfen und sich dann zu überlegen, ob man das auf zwei Tabellen auftrennen muss und aus welchen Gründen. (Eigentlich kann es höchstens Performancegründe haben, die Übersichtlichkeit sollte man auch mit nem View hinbekommen).
        Bei dem was Du beschrieben hast, wird ja die Tabelle der aktuellen Daten automatisch synchronisiert. Das stelle ich mir über Trigger schon etwas unschön vor, wenn man es gar in der Anwendungslogik regelt, ist es richtig fehleranfällig.
        Im Wesentlichen wollte ich aber darauf hinweisen, dass der OP das nicht so lösen sollte, weil es irgendwie üblich ist das so zu tun. Wenn er das so macht, sollte er schon wissen, wieso.

        Grüße

        Daniel