none
Uhrzeit, wo keine hingehört RRS feed

  • Frage

  • Hallo zusammen,

    hin und wieder taucht in einer von mir entwickelten Anwendung ein sehr merkwürdiges Phänomen mit fatalen Folgen auf. In mehreren zusammen hängenden SPs werden Daten auf der Basis von Datumswerten bearbeitet. Die Berechnungen sind recht komplex und im Einzelnen hier nicht von Belang. Wichtig ist, dass in der Datenbank normalerweise nur Datumswerte ohne Uhrzeiten gespeichert werden und alle Berechnungen nur auf Datumsebene (in Form von z.B. DATEDIFF(d, Datum1, Datum2) und DATEADD(d, 1, Datum)) erfolgen. Uhrzeiten werden bei diesen Berechnungen nirgendwo gebraucht.

    Die Änderungen an den Datensätzen werden in einer eigenen Tabelle geloggt, so dass ich im Bilde bin, welche Änderungen stattfinden. In dieser Tabelle gibt es u.a. Felder für "AltesDatum", "NeuesDatum" und für einen Timestamp, an dem die Änderung in die DB geschrieben wurde. Wie aus dem Nichts tauchen zuweilen in den dann auch in der DB gespeicherten SP-Variablen Uhrzeiten auf, die im Feld "NeuesDatum" gespeichert werden. Die Uhrzeit liegt immer etwas vor der Uhrzeit, die im Timestamp-Feld gespeichert wird.

    Im Laufe des Tages taucht genau diese Uhrzeit in ganz anderen Datensätzen ebenfalls auf, die mit denen, in denen der Fehler ursprünglich aufgetreten ist, nichts weiter zu tun haben als häufig den gleichen Benutzer, der die erste Transaktion einst angestoßen hat. Zwischen dem ersten Fehler und den nächsten können z.T. Stunden liegen. Das Datum, das mit der Uhrzeit zusammen gespeichert wird, kann ein völlig anderes sein.

    Mir kommt es so vor, als ob diese "Geisteruhrzeiten" irgendwo im Speicher des  Servers herumschwirren und sich an Datumswerte hängen, die zufällig in diesen Speicherbereich geschrieben werden. Ist so etwas denkbar?

    Für jeden Hinweis bin ich dankbar.

    Viele Grüße,
    Michael Schörner

    Montag, 8. Oktober 2012 15:40

Antworten

  • Hallo zusammen,

    es scheint, Gott sei Dank, keine "vagabundierenden" Uhrzeiten im SQL Server zu geben - nur nachlässige Programmierer. Ich habe eine Stelle in einer SP gefunden, bei der tatsächlich eine Uhrzeit unter ganz bestimmten Bedingungen in eine Variable hätte gelangen können. Das Loch ist mittlerweile gefixt.

    Allen, die sich mit mir zusammen den Kopf zerbrochen haben, möchte ich danken.

    Viele Grüße,
    Michael Schörner

    Montag, 15. Oktober 2012 11:55

Alle Antworten

  • Hallo Michael,

    "Geisteruhrzeiten" könnte es allerhöchstens geben, wenn deine Datenbank hinüber ist. Aber aufgrund deiner Schilderung mag ich daran nicht wirklich glauben.

    Es wäre wahrscheinlich sinnvoller, sich zu fragen, wer und/oder was ändert/speichert diese Werte. Von alleine kommen die nicht da rein. Ich denke eher, dass eine SP falsch programmiert ist oder dass von anderer Stelle aus schreibend auf die Datenbank zugegriffen und dabei dann keine Rücksicht auf deine Vorgaben bzgl. Uhrzeit genommen wird.

    Ich persönlich würde - zumindest zeitweise - eine vollständige Protokollierung sämtlicher Änderungen vornehmen. Das geht bspw. mit entsprechenden Triggern auf jede Tabelle, die die geänderten Daten in eine Protokolltabelle schreiben. Alternativ schau dir mal das hier an:

      http://msdn.microsoft.com/de-de/library/cc280424.aspx


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Montag, 8. Oktober 2012 16:08
    Moderator
  • Hallo Michael,

    da stimme ich Stefan zu, der SQL Server fügt nicht aus Langeweile Uhrzeiten zu Datumswerten hinzu; er macht was man ihm sagt. Entweder hast Du irgendwo einen Bug oder jemand arbeitet an den Stored Procedure dran vorbei.


    Olaf Helper

    Blog Xing

    Montag, 8. Oktober 2012 17:33
  • Hallo Olaf,

    falls der SQL Server (und der [virtuelle] Windows Server, auf dem dieser läuft) keine Uhrzeiten aus dem Nichts schöpft, bleibt nur die Möglichkeit, dass die Uhrzeit vom Clientprogramm (Access-ADE) generiert wird. Ich bin jeglichen Code mehrfach durchgegangen, ohne eine Stelle zu finden, an der das passieren könnte. Zumal die Uhrzeit "vererbt" wird, d.h. an Daten ganz anderer Datensätze zu ganz anderen Zeiten angehängt wird.

    Beispiele aus dem Transaktionslog:

    ID         Termin   Rücknahmedatum                 Verfügbardatum                    NeuesVerfügbardatum         Timestamp
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------
    7109    57159    2012-10-09 00:00:00.000    2012-10-10 00:00:00.000    2012-10-19 09:25:29.320    2012-10-08 09:25:33.523 (hier erscheint die Uhrzeit erstmalig)
    7124    56938    2012-10-11 00:00:00.000    2012-10-18 00:00:00.000    2012-10-16 09:25:29.320    2012-10-08 12:16:12.513
    7143    56732    2012-10-04 00:00:00.000    2012-10-18 00:00:00.000    2012-10-16 09:25:29.320    2012-10-08 16:14:18.943

    Weder die aufrufende Clientfunktion noch die SPs im SQL Server speichern diese Daten irgendwo zwischen. Ich könnte ja noch verstehen, wenn ein Fehler immer neue Uhrzeiten generiert, aber dass er die gleiche immer wieder recyclet, bleibt mir ein Rätsel?

    Diese Funktionen werden täglich zigmal ausgeführt und laufen zu 98% problemlos. Neben der Spur lassen sich hier keine Daten ins System bringen. Der Benutzer stößt den Prozess nur an, der dann automatisch abläuft. Auffällig ist, dass der Fehler in den meisten Fällen morgens zwischen acht und zehn Uhr auftritt und in den meisten Fällen nur bei ganz bestimmten Benutzern. Die Abweichung der Uhrzeit von "NeuesVerfügbardatum" und "Timestamp" resultiert wahrscheinlich daher, dass die Uhrzeit zu Beginn der Transaktion erzeugt wird, während der Timstamp gesetzt wird, wenn die geänderten Daten in die DB zurückgeschrieben werden. Die ganze Transaktion ist recht komplex und dauert eine zeitlang.

    Gruß,
    Michael

    Dienstag, 9. Oktober 2012 07:36
  • Hallo Stefan,

    danke für den Tipp. Wenn alle Stricke reißen, muss ich wohl alle Parameter der Transaktion(en) auch auf der Clientseite loggen. Und ich möchte wetten, dass dann der Fehler wochenlang nicht mehr auftritt ;-)

    Gruß,
    Michael

    Dienstag, 9. Oktober 2012 07:39
  • Wenn du keinen Zeitanteil brauchst, dann solltest du den DATE Datentypen verwenden (ab SQL Server 2008). Ansonsten sollte ein Trigger die Zeitanteile entfernen.
    Dienstag, 9. Oktober 2012 07:42
    Moderator
  • Am 09.10.2012 09:36, schrieb Michael Schörner:
    > Hallo Olaf,
    >
    > falls der SQL Server (und der [virtuelle] Windows Server, auf dem dieser
    > läuft) keine Uhrzeiten aus dem Nichts schöpft, bleibt nur die
    > Möglichkeit, dass die Uhrzeit vom Clientprogramm (Access-ADE) generiert
    > wird. Ich bin jeglichen Code mehrfach durchgegangen, ohne eine Stelle zu
    > finden, an der das passieren könnte. Zumal die Uhrzeit "vererbt" wird,
    > d.h. an Daten ganz anderer Datensätze zu ganz anderen Zeiten angehängt wird.
    >
    > Beispiele aus dem Transaktionslog:
    >
    > ID         Termin   Rücknahmedatum                 Verfügbardatum
    >               NeuesVerfügbardatum         Timestamp
    > ------------------------------------------------------------------------------------------------------------------------------------------------------------------
    > 7109    57159    2012-10-09 00:00:00.000    2012-10-10 00:00:00.000
    >   2012-10-19 09:25:29.320    2012-10-08 09:25:33.523 (hier erscheint die
    > Uhrzeit erstmalig)
     
    Bin auch überzeugt, daß die Daten irgendwo geschrieben werden.
     
    Wird im Access evtl irgendwo mit Now() anstatt Date() gearbeitet?
    Obwohl ich bisher davon überzeugt war, daß Access keine Tausendstel
    kennt - was dafür spricht, daß der Wert aus dem SQL-Server kommt.
    Prüfe Stellen an denen du mit GETDATE() arbeitest.
    Prüfe ob DEFAULT-Werte in den Tabellen eingestellt sind.
    Prüfe ob es Trigger gibt, die vielleicht Datumswerte setzen.
     
    Wie machst du eigentlich dein Logging?
    Evtl kannst du dort auch speichern, welcher Nutzer von welchem Host etc
    den Datensatz ändert.
     
    Lutz
     
    Dienstag, 9. Oktober 2012 11:06
  • Hallo Stefan,

    der Server ist leider ein 2005er. Die Idee mit dem Trigger hatte ich auch schon, allerdings wär´s mir lieber, ich finde die Wurzel des Problems.

    Gruß,
    Michael

    Dienstag, 9. Oktober 2012 14:24
  • Hallo Lutz,

    in den SPs wird GETDATE() and zwei Stellen verwendet, um einen Grenzwert zu bestimmen (SET @grenzwert = DATEADD(d, 2, GETDATE())). Alle Operationen mit diesem Wert laufen dann über DATEDIFF(d, @grenzwert, @datum). Ein "Überspringen" der Uhrzeit im Grenzwert sollte unmöglich sein, da der Grenzwert nie einer anderen Variable zugeordnet wird, mit der weitergerechnet wird.

    Um diese unmögliche Möglichkeit gänzlich auszuschließen, habe ich nun vor der Zuweisung der Grenzvariablen noch eine Funktion geschaltet, die den Uhrzeitanteil entfernt. Mal schauen, was dabei heraus kommt.

    Gruß,
    Michael

    Dienstag, 9. Oktober 2012 14:32
  • Hallo Michael,

    GETDATE() liefert, anders der Name es vermuten lassen würde, die Uhrzeit mit.

      SELECT DATEADD(d, 2, GETDATE())

    liefert also bspw. das hier:

      2012-10-11 16:44:18.840

    Was Du nun aber mit Grenzwert überspringen, ... meinst, weiß ich nicht.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Dienstag, 9. Oktober 2012 14:45
    Moderator
  • Hallo Stefan,

    dass GETDATE() die Uhrzeit mitliefert, weiß ich. Deshalb entferne ich ja nun auch die Uhrzeit, bevor ich das Datum der Variablen zuweise, die den Grenzwert hält.

    Mit "Überspringen" meine ich, das "Wandern" der Uhrzeit aus einer Variablen in eine andere, ohne dass es zu einer expliziten Zuweisung kommt. Ich weiß, dass das unmöglich ist (jedenfalls, wenn alles so funktioniert, wie es soll).

    Ich warte jetzt erst einmal ab, ob der Fehler wieder einmal auftaucht, und forsche dann weiter. Leider kann es sein, dass es Wochen dauert, bis der Fehler erneut auftritt. 

    Gruß,
    Michael

    Dienstag, 9. Oktober 2012 15:01
  • Imho liegt es genau da. Denn dein Datenmodell scheint ja DATETIME-Angaben in der Form ohne Zeitanteil zu benötigen. Das ist für mich ein Business Constraint der durch die Datenbank, mittels Trigger in diesem Fall, durchgesetzt werden muss. Alternativ geht auch ein CHECK Constraint.

    USE tempdb;
    
    CREATE TABLE Test
        (
          ID INT IDENTITY ,
          dt DATETIME NOT NULL
                      CHECK ( dt = DATEADD(DAY, 0, DATEDIFF(DAY, 0, dt)) )
        );
    go
    
    PRINT 'Good';
    INSERT  INTO Test
            ( dt )
    VALUES  ( '20121001' );
    go
    
    PRINT 'Bad';
    INSERT  INTO Test
            ( dt )
    VALUES  ( GETDATE() );
    go
    
    PRINT 'Result';
    SELECT  *
    FROM    Test;
    go
    
    DROP TABLE Test;
    go

    Dienstag, 9. Oktober 2012 15:05
    Moderator
  • Hallo zusammen,

    es scheint, Gott sei Dank, keine "vagabundierenden" Uhrzeiten im SQL Server zu geben - nur nachlässige Programmierer. Ich habe eine Stelle in einer SP gefunden, bei der tatsächlich eine Uhrzeit unter ganz bestimmten Bedingungen in eine Variable hätte gelangen können. Das Loch ist mittlerweile gefixt.

    Allen, die sich mit mir zusammen den Kopf zerbrochen haben, möchte ich danken.

    Viele Grüße,
    Michael Schörner

    Montag, 15. Oktober 2012 11:55
  • Hallo Michael,

    prima, dass es nun funktioniert. Es wäre für andere, die evtl. mal dasselbe Problem haben aber sinnvoll, wenn Du die Postings, die auf den Fehler - der sich ja nun bewahrheitet hat - hinweisen, als Antwort markieren würdest.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Dienstag, 16. Oktober 2012 18:37
    Moderator