Ich habe einen Bericht, der die Anzahl der Ereignisse der letzten 12 Stunden nach Stunden gruppiert anzeigt. Hört sich einfach an, aber ich habe Probleme damit, Aufzeichnungen aufzunehmen, die die Lücken schließen.
Hier ist eine Beispieltabelle:
Event
(
EventTime datetime,
EventType int
)
Die Daten sehen folgendermaßen aus:
'2012-03-08 08:00:04', 1
'2012-03-08 09:10:00', 2
'2012-03-08 09:11:04', 2
'2012-03-08 09:10:09', 1
'2012-03-08 10:00:17', 4
'2012-03-08 11:00:04', 1
Ich muss eine Ergebnismenge erstellen, die für jede Stunde der letzten 12 Stunden einen Datensatz enthält, unabhängig davon, ob Ereignisse in dieser Stunde vorliegen oder nicht.
Unter der Annahme, dass die aktuelle Zeit '2012-03-08 11:00:00' ist, würde der Bericht (ungefähr) Folgendes anzeigen:
Hour EventCount
---- ----------
23 0
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 1
9 3
10 1
Ich habe eine Lösung gefunden, die eine Tabelle verwendet, die einen Datensatz für jede Stunde des Tages enthält. Ich habe es geschafft, die gewünschten Ergebnisse zu erzielen, indem ich eine UNION und eine verworrene Falllogik in der where-Klausel verwendet habe, aber ich hatte gehofft, dass jemand eine elegantere Lösung hat.
quelle
Tally-Tabellen können für solche Dinge verwendet werden. Sie können sehr effizient sein. Erstellen Sie die Tabelle unten. Ich habe die Tabelle mit nur 24 Zeilen für Ihr Beispiel erstellt, aber Sie können sie mit beliebig vielen erstellen, die Sie für andere Zwecke verwenden möchten.
Ich habe angenommen, Ihre Tabelle heißt dbo.tblEvents. Führen Sie die folgende Abfrage aus. Ich glaube, das ist was Sie suchen:
Ich glaube, die folgenden Links sind dafür verantwortlich. Ich glaube, hier bin ich zum ersten Mal auf Folgendes gestoßen:
http://www.sqlservercentral.com/articles/T-SQL/62867/
http://www.sqlservercentral.com/articles/T-SQL/74118/
quelle
Erstens entschuldige ich mich für die Verzögerung meiner Antwort seit meinen letzten Kommentaren.
In den Kommentaren wurde darauf hingewiesen, dass die Verwendung eines rekursiven CTE (ab hier rCTE) aufgrund der geringen Zeilenanzahl schnell genug ist. Auch wenn es so scheint, könnte nichts weiter von der Wahrheit entfernt sein.
BUILD TALLY TABLE UND TALLY FUNCTION
Bevor wir mit dem Testen beginnen, müssen wir eine physische Tally-Tabelle mit dem entsprechenden Clustered-Index und einer Tally-Funktion im Itzik-Ben-Gan-Stil erstellen. Wir werden das alles auch in TempDB machen, damit wir nicht versehentlich die Goodies von irgendjemandem fallen lassen.
Hier ist der Code zum Erstellen der Tally-Tabelle und meine aktuelle Produktionsversion von Itziks wunderbarem Code.
Übrigens ... Beachten Sie, dass in ungefähr einer Sekunde eine Million und eine Zeile Tally Table erstellt und ein Clustered Index hinzugefügt wurde. Versuchen Sie das mit einem rCTE und sehen Sie, wie lange es dauert! ;-)
ERSTELLEN SIE EINIGE TESTDATEN
Wir brauchen auch einige Testdaten. Ja, ich stimme zu, dass alle Funktionen, die wir testen werden, einschließlich des rCTE, in einer Millisekunde oder weniger für nur 12 Zeilen ausgeführt werden, aber das ist die Falle, in die viele Menschen geraten. Wir werden später mehr über diese Falle sprechen, aber lassen Sie uns vorerst jeden Funktionsaufruf 40.000 Mal simulieren, dh wie oft bestimmte Funktionen in meinem Shop an einem 8-Stunden-Tag aufgerufen werden. Stellen Sie sich vor, wie oft solche Funktionen in einem großen Online-Einzelhandelsgeschäft aufgerufen werden könnten.
Hier ist also der Code zum Erstellen von 40.000 Zeilen mit zufälligen Datumsangaben, von denen jede eine Zeilennummer hat, nur zu Verfolgungszwecken. Ich habe mir nicht die Zeit genommen, ganze Stunden zu arbeiten, weil es hier keine Rolle spielt.
BAUEN SIE EINIGE FUNKTIONEN, UM DIE 12-REIHEN-STUNDEN-SACHE ZU TUN
Als nächstes habe ich den rCTE-Code in eine Funktion konvertiert und 3 weitere Funktionen erstellt. Sie wurden alle als leistungsstarke iTVFs (Inline Table Valued Functions) erstellt. Sie können immer sagen, dass iTVFs keinen BEGIN enthalten, wie dies bei Scalar oder mTVFs (Multi-Statement Table Valued Functions) der Fall ist.
Hier ist der Code zum Erstellen dieser 4 Funktionen ... Ich habe sie nach der Methode benannt, die sie verwenden, und nicht nach dem, was sie tun, um es einfacher zu machen, sie zu identifizieren.
BAUEN SIE DAS TESTGURT, UM DIE FUNKTIONEN ZU TESTEN
Last but not least brauchen wir ein Testgeschirr. Ich mache einen Baseline-Check und teste dann jede Funktion auf identische Weise.
Hier ist der Code für das Testgeschirr ...
Eine Sache, die im obigen Testgeschirr zu beachten ist, ist, dass ich alle Ausgaben in "Wegwerf" -Variablen umleite. Das ist, um zu versuchen, die Leistungsmessungen so rein wie möglich zu halten, ohne dass Ergebnisse auf der Festplatte oder auf dem Bildschirm angezeigt werden.
VORSICHT BEI STATISTIKEN
Ein Hinweis zur Vorsicht für angehende Tester ... Sie dürfen SET STATISTICS NICHT verwenden, wenn Sie entweder die Skalar- oder die mTVF-Funktion testen. Es kann nur mit iTVF-Funktionen wie den in diesem Test beschriebenen sicher verwendet werden. SET STATISTICS führt nachweislich dazu, dass SCALAR-Funktionen hunderte Male langsamer ausgeführt werden, als dies tatsächlich der Fall ist. Ja, ich versuche, eine andere Windmühle zu kippen, aber das wäre ein ganzer Artikel, für den ich keine Zeit habe. Ich habe einen Artikel auf SQLServerCentral.com, in dem das alles behandelt wird, aber es macht keinen Sinn, den Link hier zu posten, da sich irgendjemand in dieser Hinsicht aus der Form bringen wird.
DIE TESTERGEBNISSE
Hier sind die Testergebnisse, wenn ich das Testkabel auf meinem kleinen i5-Laptop mit 6 GB RAM laufen lasse.
Die "BASELINE SELECT", die nur Daten auswählt (jede Zeile wurde 12-mal erstellt, um dasselbe Rücklaufvolumen zu simulieren), kam ungefähr in einer Fünftelsekunde. Alles andere kam in einer Viertelsekunde. Nun, alles außer dieser verdammten rCTE-Funktion. Es dauerte 4 und 1/4 Sekunden oder 16 Mal länger (1.600% langsamer).
Und sehen Sie sich die logischen Lesevorgänge (Speicher-E / A) an ... Der rCTE verbrauchte satte 2.960.000 (fast 3 MILLION Lesevorgänge), während die anderen Funktionen nur etwa 82.100 verbrauchten. Das bedeutet, dass der rCTE mehr als 34,3-mal mehr Speicher-E / A verbraucht als alle anderen Funktionen.
SCHLIESSENDE GEDANKEN
Lassen Sie uns zusammenfassen. Die rCTE-Methode für diese "kleine" 12-Zeilen-Sache verwendete 16-mal (1.600%) mehr CPU (und Dauer) und 34,3-mal (3.430%) mehr Speicher-E / A als jede der anderen Funktionen.
Heh ... ich weiß was du denkst. "Big Deal! Es ist nur eine Funktion."
Ja, einverstanden, aber wie viele andere Funktionen haben Sie? Wie viele andere Orte außerhalb von Funktionen haben Sie? Und haben Sie welche, die mit mehr als nur 12 Zeilen pro Lauf arbeiten? Und gibt es eine Chance, dass jemand, der für eine Methode im Stich ist, diesen rCTE-Code für etwas viel Größeres kopiert?
Ok, Zeit stumpf zu sein. Es macht absolut keinen Sinn, Code mit Leistungsproblemen zu rechtfertigen, nur weil die Anzahl der Zeilen oder deren Verwendung begrenzt sein soll. Abgesehen davon, dass Sie eine MPP-Box für vielleicht Millionen von Dollar kaufen (ganz zu schweigen von den Kosten für das Umschreiben von Code, damit dieser auf einem solchen Computer funktioniert), können Sie keine Maschine kaufen, auf der Ihr Code 16-mal schneller ausgeführt wird (SSDs haben gewonnen) tu es auch nicht ... all dieses Zeug war im Hochgeschwindigkeitsspeicher (als wir es getestet haben). Leistung ist im Code. Gute Leistung steckt in gutem Code.
Können Sie sich vorstellen, dass Ihr gesamter Code "nur" 16-mal schneller lief?
Begründen Sie niemals schlechten oder leistungsgestörten Code bei geringer Zeilenanzahl oder sogar geringer Nutzung. Wenn Sie dies tun, müssen Sie möglicherweise eine der Windmühlen ausleihen, bei denen mir vorgeworfen wurde, sie zu neigen, um Ihre CPUs und Festplatten kühl genug zu halten. ;-)
EIN WORT ÜBER DAS WORT "TALLY"
Ja ich stimme zu. Semantisch gesehen enthält die Tally-Tabelle Zahlen, keine "Tallies". In meinem ursprünglichen Artikel zum Thema (es war nicht der ursprüngliche Artikel zur Technik, aber es war mein erster) habe ich es "Tally" genannt, nicht aufgrund dessen, was es enthält, sondern aufgrund dessen, was es tut ... es ist verwendet, um zu "zählen", anstatt zu schleifen, und um etwas zu "zählen", um etwas zu "zählen". ;-) Nenn es wie du willst ... Nummerntabelle, Tallytabelle, Sequenztabelle, was auch immer. Ist mir egal Für mich bedeutet "Tally" mehr "voll" und enthält als guter fauler DBA nur 5 Buchstaben (2 sind identisch) anstelle von 7, was für die meisten Leute einfacher zu sagen ist. Es ist auch "Singular", was meiner Namenskonvention für Tabellen folgt. ;-) Es ist Es ist auch das, was der Artikel, der eine Seite aus einem Buch aus den 60er Jahren enthielt, so nannte. Ich werde es immer als "Tally Table" bezeichnen und Sie werden immer noch wissen, was ich oder jemand anderes bedeutet. Ich vermeide auch die ungarische Notation wie die Pest, nenne aber die Funktion "fnTally", so dass ich sagen könnte "Wenn Sie die von mir gezeigte eff-en Tally-Funktion verwenden würden, hätten Sie kein Leistungsproblem", ohne dass es tatsächlich eine wäre HR Verletzung. ;-) ohne dass es sich tatsächlich um eine HR-Verletzung handelt. ;-) ohne dass es sich tatsächlich um eine HR-Verletzung handelt. ;-)
Was mich mehr beunruhigt, ist, dass die Leute lernen, es richtig zu verwenden, anstatt auf Dinge wie leistungsbehinderte rCTEs und andere Formen von versteckten RBAR zurückzugreifen.
quelle
Sie müssen
RIGHT JOIN
Ihre Daten mit einer Abfrage versehen, die einen Datensatz für jede Stunde zurückgibt, die Sie benötigen.Sehen Sie dies für ein paar Möglichkeiten , um ein Zeilennummer zu erhalten , die Sie dann als Stunden von der aktuellen Zeit abziehen könnten.
In Oracle generiert eine hierarchische Abfrage auf duale Zeilen:
quelle