Kennen Sie eine einfache Möglichkeit, einen Datensatz für jede Stunde der letzten 12 Stunden zu erstellen?

12

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.

datagod
quelle

Antworten:

21

Für SQL Server 2005+ können Sie diese 12 Datensätze sehr einfach mit einer Schleife oder einem rekursiven CTE generieren. Hier ist ein Beispiel für einen rekursiven CTE:

DECLARE @Date DATETIME
SELECT @Date = '20120308 11:00:00'

;WITH Dates AS
(
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,@Date)) [Hour], 
      DATEADD(HOUR,-1,@Date) [Date], 1 Num
    UNION ALL
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,[Date])), 
      DATEADD(HOUR,-1,[Date]), Num+1
    FROM Dates
    WHERE Num <= 11
)
SELECT [Hour], [Date]
FROM Dates

Dann brauchen Sie nur noch Ihren Veranstaltungstisch anzuschließen.

Lamak
quelle
2
Ich fand das gleich nachdem du gepostet hast. explainextended.com/2009/10/21/... Es zeigt an, dass für diesen Zweck einen CTE mit weniger effizient als einer gespeicherten Tabelle. Ist das wahr? Wie Nick sagte, spielt es wahrscheinlich keine Rolle für diesen Fall, aber ...
Leigh Riffel
4
Ich denke, dass es bei einer größeren Anzahl von Zeilen einen Unterschied machen würde, wenn Sie 12 Datensätze benötigen, dann wird es überhaupt keinen Leistungseinbruch geben
Lamak
Lamak und @swasheck. Heh ... ich bin etwas spät dran (habe den Überblick über diesen Thread verloren), aber kein Problem. Siehe die Antwort, die ich schließlich zur Unterstützung meiner Ansprüche oben gepostet habe. Und denken Sie daran, jeder Code hat eine kumulative Wirkung. Wenn alle Code-Leute "nur" 16-mal schneller wären, wäre die Hälfte der Posts in solchen Foren nicht mehr nötig. Und es dauert nicht länger (manchmal kürzer), um schnelleren Code zu schreiben.
Jeff Moden
10

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.

SELECT TOP 24 
        IDENTITY(INT,1,1) AS N
   INTO dbo.Tally
   FROM Master.dbo.SysColumns sc1,
        Master.dbo.SysColumns sc2

--===== Add a Primary Key to maximize performance
  ALTER TABLE dbo.Tally
    ADD CONSTRAINT PK_Tally_N 
        PRIMARY KEY CLUSTERED (N) WITH FILLFACTOR = 100

Ich habe angenommen, Ihre Tabelle heißt dbo.tblEvents. Führen Sie die folgende Abfrage aus. Ich glaube, das ist was Sie suchen:

SELECT t.n, count(e.EventTime)
FROM dbo.Tally t
LEFT JOIN dbo.tblEvent e  on t.n = datepart(hh, e.EventTime)
GROUP BY t.n
ORDER BY t.n

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/

Henry Lee
quelle
+1 aber semantisch ist es eine Tabelle mit Zahlen, keine Tabelle mit Zahlen.
Aaron Bertrand
1
Eine der Definitionen von "Tally" ist "To Count". Die "Tally Table" ist nach dem "Tally Stick" benannt, einem langen, dünnen Stick, mit dem gezählt wird.
Jeff Moden
7

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.

--===== Do this in a nice, safe place that everyone has
    USE tempdb
;
--===== Create/Recreate a Physical Tally Table
     IF OBJECT_ID('dbo.Tally','U') IS NOT NULL
        DROP TABLE dbo.Tally
;
     -- Note that the ISNULL makes a NOT NULL column
 SELECT TOP 1000001
        N = ISNULL(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1,0)
   INTO dbo.Tally
   FROM      sys.all_columns ac1
  CROSS JOIN sys.all_columns ac2
;
  ALTER TABLE dbo.Tally
    ADD CONSTRAINT PK_Tally PRIMARY KEY CLUSTERED (N)
;
--===== Create/Recreate a Tally Function
     IF OBJECT_ID('dbo.fnTally','IF') IS NOT NULL
        DROP FUNCTION dbo.fnTally
;
GO
 CREATE FUNCTION [dbo].[fnTally]
/**********************************************************************************************************************
 Purpose:
 Return a column of BIGINTs from @ZeroOrOne up to and including @MaxN with a max value of 1 Trillion.

 As a performance note, it takes about 00:02:10 (hh:mm:ss) to generate 1 Billion numbers to a throw-away variable.

 Usage:
--===== Syntax example (Returns BIGINT)
 SELECT t.N
   FROM dbo.fnTally(@ZeroOrOne,@MaxN) t
;

 Notes:
 1. Based on Itzik Ben-Gan's cascading CTE (cCTE) method for creating a "readless" Tally Table source of BIGINTs.
    Refer to the following URLs for how it works and introduction for how it replaces certain loops. 
    http://www.sqlservercentral.com/articles/T-SQL/62867/
    http://sqlmag.com/sql-server/virtual-auxiliary-table-numbers
 2. To start a sequence at 0, @ZeroOrOne must be 0 or NULL. Any other value that's convertable to the BIT data-type
    will cause the sequence to start at 1.
 3. If @ZeroOrOne = 1 and @MaxN = 0, no rows will be returned.
 5. If @MaxN is negative or NULL, a "TOP" error will be returned.
 6. @MaxN must be a positive number from >= the value of @ZeroOrOne up to and including 1 Billion. If a larger
    number is used, the function will silently truncate after 1 Billion. If you actually need a sequence with
    that many values, you should consider using a different tool. ;-)
 7. There will be a substantial reduction in performance if "N" is sorted in descending order.  If a descending 
    sort is required, use code similar to the following. Performance will decrease by about 27% but it's still
    very fast especially compared with just doing a simple descending sort on "N", which is about 20 times slower.
    If @ZeroOrOne is a 0, in this case, remove the "+1" from the code.

    DECLARE @MaxN BIGINT; 
     SELECT @MaxN = 1000;
     SELECT DescendingN = @MaxN-N+1 
       FROM dbo.fnTally(1,@MaxN);

 8. There is no performance penalty for sorting "N" in ascending order because the output is explicity sorted by
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL))

 Revision History:
 Rev 00 - Unknown     - Jeff Moden 
        - Initial creation with error handling for @MaxN.
 Rev 01 - 09 Feb 2013 - Jeff Moden 
        - Modified to start at 0 or 1.
 Rev 02 - 16 May 2013 - Jeff Moden 
        - Removed error handling for @MaxN because of exceptional cases.
 Rev 03 - 22 Apr 2015 - Jeff Moden
        - Modify to handle 1 Trillion rows for experimental purposes.
**********************************************************************************************************************/
        (@ZeroOrOne BIT, @MaxN BIGINT)
RETURNS TABLE WITH SCHEMABINDING AS 
 RETURN WITH
  E1(N) AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1)                                  --10E1 or 10 rows
, E4(N) AS (SELECT 1 FROM E1 a, E1 b, E1 c, E1 d)      --10E4 or 10 Thousand rows
,E12(N) AS (SELECT 1 FROM E4 a, E4 b, E4 c)            --10E12 or 1 Trillion rows                 
            SELECT N = 0 WHERE ISNULL(@ZeroOrOne,0)= 0 --Conditionally start at 0.
             UNION ALL 
            SELECT TOP(@MaxN) N = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E12 -- Values from 1 to @MaxN
;
GO

Ü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.

--===== Do this in a nice, safe place that everyone has
    USE tempdb
;
--===== Create/Recreate a Test Date table
     IF OBJECT_ID('dbo.TestDate','U') IS NOT NULL
        DROP TABLE dbo.TestDate
;
DECLARE  @StartDate DATETIME
        ,@EndDate   DATETIME
        ,@Rows      INT
;
 SELECT  @StartDate = '2010' --Inclusive
        ,@EndDate   = '2020' --Exclusive
        ,@Rows      = 40000  --Enough to simulate an 8 hour day where I work
;
 SELECT  RowNum       = IDENTITY(INT,1,1)
        ,SomeDateTime = RAND(CHECKSUM(NEWID()))*DATEDIFF(dd,@StartDate,@EndDate)+@StartDate
   INTO dbo.TestDate
   FROM dbo.fnTally(1,@Rows)
;

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.

--=====  CREATE THE iTVFs
--===== Do this in a nice, safe place that everyone has
    USE tempdb
;
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.OriginalrCTE','IF') IS NOT NULL
        DROP FUNCTION dbo.OriginalrCTE
;
GO
 CREATE FUNCTION dbo.OriginalrCTE
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
WITH Dates AS
(
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,@Date)) [Hour], 
      DATEADD(HOUR,-1,@Date) [Date], 1 Num
    UNION ALL
    SELECT DATEPART(HOUR,DATEADD(HOUR,-1,[Date])), 
      DATEADD(HOUR,-1,[Date]), Num+1
    FROM Dates
    WHERE Num <= 11
)
SELECT [Hour], [Date]
FROM Dates
GO
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.MicroTally','IF') IS NOT NULL
        DROP FUNCTION dbo.MicroTally
;
GO
 CREATE FUNCTION dbo.MicroTally
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
 SELECT  [Hour] = DATEPART(HOUR,DATEADD(HOUR,t.N,@Date))
        ,[DATE] = DATEADD(HOUR,t.N,@Date)
   FROM (VALUES (-1),(-2),(-3),(-4),(-5),(-6),(-7),(-8),(-9),(-10),(-11),(-12))t(N)
;
GO
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.PhysicalTally','IF') IS NOT NULL
        DROP FUNCTION dbo.PhysicalTally
;
GO
 CREATE FUNCTION dbo.PhysicalTally
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
 SELECT  [Hour] = DATEPART(HOUR,DATEADD(HOUR,-t.N,@Date))
        ,[DATE] = DATEADD(HOUR,-t.N,@Date)
   FROM dbo.Tally t
  WHERE N BETWEEN 1 AND 12
;
GO
-----------------------------------------------------------------------------------------
     IF OBJECT_ID('dbo.TallyFunction','IF') IS NOT NULL
        DROP FUNCTION dbo.TallyFunction
;
GO
 CREATE FUNCTION dbo.TallyFunction
        (@Date DATETIME)
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
 SELECT  [Hour] = DATEPART(HOUR,DATEADD(HOUR,-t.N,@Date))
        ,[DATE] = DATEADD(HOUR,-t.N,@Date)
   FROM dbo.fnTally(1,12) t
;
GO

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 ...

PRINT '--========== Baseline Select =================================';
DECLARE @Hour INT, @Date DATETIME
;
    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = RowNum
        ,@Date = SomeDateTime
   FROM dbo.TestDate
  CROSS APPLY dbo.fnTally(1,12);
    SET STATISTICS TIME,IO OFF;
GO
PRINT '--========== Orginal Recursive CTE ===========================';
DECLARE @Hour INT, @Date DATETIME
;

    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.OriginalrCTE(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO
PRINT '--========== Dedicated Micro-Tally Table =====================';
DECLARE @Hour INT, @Date DATETIME
;

    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.MicroTally(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO
PRINT'--========== Physical Tally Table =============================';
DECLARE @Hour INT, @Date DATETIME
;
    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.PhysicalTally(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO
PRINT'--========== Tally Function ===================================';
DECLARE @Hour INT, @Date DATETIME
;
    SET STATISTICS TIME,IO ON;
 SELECT  @Hour = fn.[Hour]
        ,@Date = fn.[Date]
   FROM dbo.TestDate td
  CROSS APPLY dbo.TallyFunction(td.SomeDateTime) fn;
    SET STATISTICS TIME,IO OFF;
GO

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.

--========== Baseline Select =================================
Table 'Worktable'. Scan count 1, logical reads 82309, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 203 ms,  elapsed time = 206 ms.
--========== Orginal Recursive CTE ===========================
Table 'Worktable'. Scan count 40001, logical reads 2960000, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 4258 ms,  elapsed time = 4415 ms.
--========== Dedicated Micro-Tally Table =====================
Table 'Worktable'. Scan count 1, logical reads 81989, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 234 ms,  elapsed time = 235 ms.
--========== Physical Tally Table =============================
Table 'Worktable'. Scan count 1, logical reads 81989, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Tally'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 250 ms,  elapsed time = 252 ms.
--========== Tally Function ===================================
Table 'Worktable'. Scan count 1, logical reads 81989, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TestDate'. Scan count 1, logical reads 105, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 250 ms,  elapsed time = 253 ms.

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.

Jeff Moden
quelle
2

Sie müssen RIGHT JOINIhre 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:

SELECT to_char(sysdate-level/24,'HH24') FROM dual CONNECT BY Level <=24;
Leigh Riffel
quelle
Es ist die "Abfrage, die einen Datensatz für jede Stunde zurückgibt", mit der ich Probleme habe. Ich versuche nur, eine Möglichkeit zu finden, 12 (oder 24) Datensätze mit jeder Stunde der letzten 12 (oder 24) Stunden zu generieren.
Datum