Wie Blöcke der Zeit zu konsolidieren?

8

Ich habe eine abgeleitete Tabelle mit einer Liste von relativen Sekunden zu einem Fremdschlüssel (ID):

%Vor%

Die Tabelle enthält hauptsächlich nicht überlappende Daten, aber es gibt Fälle, in denen ich ein TimeTo & lt; TimeFrom eines anderen Datensatzes:

%Vor%

Die Ergebnismenge soll ein abgeflachter linearer Leerlaufbericht sein, aber mit zu vielen dieser Überlappungen endet die negative Zeit. I.e. Wenn das obige Fenster für ID = 10 150 Sekunden lang war und ich die Differenzen der relativen Sekunden addierte, um von der Fenstergröße abzuziehen, würde ich mit 150-(20+20+90+75)=-55 enden. Diese Herangehensweise, die ich versucht habe, hat mich dazu gebracht zu erkennen, dass es Überschneidungen gab, die abgeflacht werden mussten.

Also, was ich suche, ist eine Lösung, um die Überlappungen in eine bestimmte Anzahl von Malen zu reduzieren:

%Vor%

Überlegungen: Leistung ist hier sehr wichtig, da dies Teil einer größeren Abfrage ist, die von alleine gut funktioniert, und ich möchte lieber nicht ihre Leistung beeinflussen, wenn ich ihr helfen kann.

Auf einen Kommentar bezüglich "Welche Sekunden haben ein Intervall" habe ich das für das Endergebnis versucht, und suche nach etwas mit besserer Leistung. Angepasst an mein Beispiel:

%Vor%

Das Problem, das ich mit dieser Lösung habe, ist, dass ich einen Zeilenanzahl-Spool aus der EXISTS-Abfrage im Abfrageplan mit einer Anzahl von Ausführungen gleich COUNT (C. *) habe. Ich habe die reellen Zahlen in dieser Abfrage belassen, um zu verdeutlichen, dass es am besten ist, diesen Ansatz zu umgehen. Da sogar mit einem Zeilenzählungs-Spool die Kosten der Abfrage um einiges reduziert werden, erhöht die Ausführungsanzahl die Kosten der Abfrage insgesamt ebenfalls um ein Vielfaches.

Weitere Bearbeitung: Das Endziel besteht darin, dies in eine Prozedur einzufügen, so dass Tabellenvariablen und Temp-Tabellen ebenfalls ein mögliches Werkzeug sind.

    
Jaaz Cole 24.07.2014, 21:43
quelle

5 Antworten

1

Links verbinden Sie jede Zeile mit ihrer nachfolgenden überlappenden Zeile mit demselben ID-Wert (sofern vorhanden).

Jetzt ist für jede Zeile in der Ergebnismenge von LHS left join RHS der Beitrag zur verstrichenen Zeit für die ID:

isnull(RHS.TimeFrom,LHS.TimeTo) - LHS.TimeFrom as TimeElapsed

Wenn Sie diese mit ID zusammenfassen, erhalten Sie die richtige Antwort.

Beachten Sie Folgendes:
  - gibt es keine überlappende Nachfolgerreihe, so ist die Berechnung einfach
LHS.TimeTo - LHS.TimeFrom
 - Bei einer überlappenden Nachfolgerzeile wird die Berechnung zu
(RHS.TimeFrom - LHS.TimeFrom) + (RHS.TimeTo - RHS.TimeFrom)
was vereinfacht zu
RHS.TimeTo - LHS.TimeFrom

    
Pieter Geerkens 24.07.2014, 22:44
quelle
2

OK. Ich versuche das immer noch mit nur einem SELECT . Aber das funktioniert total:

%Vor%     
Alireza 24.07.2014 23:13
quelle
0

Was ist mit etwas wie unten (geht von SQL 2008+ wegen CTE aus):

%Vor%

Ich habe nicht viele Daten zum Testen, scheint aber bei den kleineren Datensätzen, die ich habe, angemessen zu sein.

    
Earl G Elliott III 24.07.2014 23:09
quelle
0

Ich habe auch dieses Problem umgangen - und schließlich habe ich festgestellt, dass das Problem Ihre Daten sind.

Sie behaupten (wenn ich das richtig verstehe), dass diese Einträge die relativen Zeiten widerspiegeln sollten, wenn ein Benutzer in den Leerlauf geht / zurückkommt.

Sie sollten sich also überlegen, Ihre Daten zu bereinigen und Ihre Einfügungen neu zu strukturieren, um gültige Datensätze zu erzeugen. Zum Beispiel die zwei Zeilen:

%Vor%

wie kann es möglich sein, dass ein Benutzer im Leerlauf ist bis Sekunde 70, aber im Leerlauf auf Sekunde 60 geht? Das bedeutet bereits, dass er spätestens um den zweiten 59 zurück ist.

Ich kann nur annehmen, dass dieses Problem von verschiedenen Threads und / oder Browserfenstern (Tabs) kommt, mit denen ein Benutzer Ihre Anwendung verwendet. (Jeder hat seine eigene "Leerlauferkennung")

Also anstatt Working-Around die Symptome - sollten Sie die Ursache beheben! Warum wird dieser Dateneintrag in die Tabelle eingefügt? Sie können dies vermeiden, indem Sie einfach überprüfen, ob der Benutzer bereits inaktiv ist, bevor Sie eine neue Zeile einfügen.

  • Erstellen Sie eine eindeutige Schlüsseleinschränkung für ID und TimeTo
  • Immer wenn ein Leerlaufereignis erkannt wird, führen Sie die folgende Abfrage aus:

    INSERT IGNORE INTO Times (ID,TimeFrom,TimeTo)VALUES('10', currentTimeStamp, -1); -- (If the user is already "idle" - nothing will happen)

  • Immer wenn ein comback-event erkannt wird, führen Sie die folgende Abfrage aus:

    UPDATE Times SET TimeTo=currentTimeStamp WHERE ID='10' and TimeTo=-1 -- (If the user is already "back" - nothing will happen)

Die Geige, die hier verlinkt ist: Ссылка würde die Ereigniskette für Ihr Beispiel reproduzieren, aber zu einem sauberen Resultat führen und logischer Satz von Leerlauffenstern:

%Vor%

Hinweis: Die Ausgabe unterscheidet sich geringfügig von der gewünschten Ausgabe. Aber ich fühle, dass dies genauer ist, aus dem oben genannten Grund: Ein Benutzer kann nicht auf der zweiten 70 in den Leerlauf gehen, ohne vorher aus seinem aktuellen Ruhezustand zurückzukehren. Er bleibt entweder im Leerlauf (und ein zweiter Thread / Tab läuft in das Idle-Event) oder er kam dazwischen.

Speziell für die Maximierung der Leistung sollten Sie die Daten korrigieren und keine Umgehungs-Abfrage erstellen. Dies ist vielleicht 3 ms nach Einfügungen, könnte aber bei Auswahl 20 Sekunden wert sein!

Bearbeiten: Wenn Multi-Threading / Mehrfachsitzungen die Ursache für die falsche Einfügung ist, müssten Sie auch eine Überprüfung implementieren, wenn most_recent_come_back_time < now() - idleTimeout - otherwhise Ein Benutzer kann auf Tab1 zurückkommen und wird nach einigen Sekunden auf Tab2 in den Ruhezustand versetzt, weil Tab2 sein Leerlaufzeitlimit überschritten hat, weil der Benutzer nur Tab1 aktualisiert hat.

    
dognose 25.07.2014 00:39
quelle
0

Ich hatte das "gleiche" Problem einmal mit "Tagen" (zusätzlich ohne WE und Feiertage zu zählen) Das Wort counting gab mir folgende Idee:

%Vor%

Sie können den Anfang auf 0 abschneiden (ich lege die '10' hier in geschweifte Klammern)

%Vor%

und schließlich

%Vor%

Zusätzlich können Sie "ignorieren" zB. 10 Sekunden, indem du dich trennst, verlierst du etwas, aber verdienst Geschwindigkeit

%Vor%

Sicher hängt es von der Reichweite ab, die Sie betrachten müssen, aber ein "Tag" oder zwei Sekunden sollten funktionieren (obwohl ich es nicht getestet habe)

Geige ...

    
halfbit 26.07.2014 16:57
quelle

Tags und Links