Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SQL, Hilfstabelle von Zahlen

Heh ... Entschuldigung, dass ich so spät auf einen alten Beitrag antworte. Und, ja, ich musste antworten, weil die beliebteste Antwort (zu der Zeit die rekursive CTE-Antwort mit dem Link zu 14 verschiedenen Methoden) in diesem Thread lautet, ähm ... bestenfalls die Leistung wird herausgefordert.

Erstens ist der Artikel mit den 14 verschiedenen Lösungen in Ordnung, um die verschiedenen Methoden zum Erstellen einer Zahlen-/Tally-Tabelle im Handumdrehen zu sehen, aber wie im Artikel und im zitierten Thread erwähnt, gibt es eine sehr wichtiges Zitat...

"Empfehlungen bezüglich Effizienz und Leistung sind oft subjektiv. Unabhängig davon, wie eine Abfrage verwendet wird, bestimmt die physische Implementierung die Effizienz einer Abfrage. Anstatt sich auf voreingenommene Richtlinien zu verlassen, ist es daher unerlässlich, dass Sie die Abfrage testen und feststellen, welche besser funktioniert."

Ironischerweise enthält der Artikel selbst viele subjektive Aussagen und "voreingenommene Richtlinien" wie "ein rekursiver CTE kann eine Nummernliste ziemlich effizient generieren " und "Das ist eine effiziente Methode der Verwendung der WHILE-Schleife aus einem Newsgroup-Beitrag von Itzik Ben-Gen" (was er sicher nur zu Vergleichszwecken gepostet hat). Kommt schon, Leute ... Nur Itziks guten Namen zu erwähnen, könnte einen armen Kerl dazu bringen, diese schreckliche Methode tatsächlich anzuwenden. Der Autor sollte üben, was er predigt, und einen kleinen Leistungstest durchführen, bevor er solche lächerlich falschen Aussagen macht, insbesondere angesichts jeglicher Skalierbarkeit.

Mit dem Gedanken, tatsächlich einige Tests durchzuführen, bevor Sie irgendwelche subjektiven Behauptungen darüber aufstellen, was ein Code tut oder was jemand "mag", ist hier ein Code, mit dem Sie Ihre eigenen Tests durchführen können. Richten Sie den Profiler für die SPID ein, von der aus Sie den Test ausführen, und überprüfen Sie es selbst ... führen Sie einfach ein "Suchen und Ersetzen" der Nummer 1000000 für Ihre "Lieblingsnummer" durch und sehen Sie ...

--===== Test for 1000000 rows ==================================
GO
--===== Traditional RECURSIVE CTE method
   WITH Tally (N) AS 
        ( 
         SELECT 1 UNION ALL 
         SELECT 1 + N FROM Tally WHERE N < 1000000 
        ) 
 SELECT N 
   INTO #Tally1 
   FROM Tally 
 OPTION (MAXRECURSION 0);
GO
--===== Traditional WHILE LOOP method
 CREATE TABLE #Tally2 (N INT);
    SET NOCOUNT ON;
DECLARE @Index INT;
    SET @Index = 1;
  WHILE @Index <= 1000000 
  BEGIN 
         INSERT #Tally2 (N) 
         VALUES (@Index);
            SET @Index = @Index + 1;
    END;
GO
--===== Traditional CROSS JOIN table method
 SELECT TOP (1000000)
        ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS N
   INTO #Tally3
   FROM Master.sys.All_Columns ac1
  CROSS JOIN Master.sys.ALL_Columns ac2;
GO
--===== Itzik's CROSS JOINED CTE method
   WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
 SELECT N
   INTO #Tally4
   FROM cteTally
  WHERE N <= 1000000;
GO
--===== Housekeeping
   DROP TABLE #Tally1, #Tally2, #Tally3, #Tally4;
GO

Wo wir gerade dabei sind, hier sind die Zahlen, die ich vom SQL Profiler für die Werte 100, 1000, 10000, 100000 und 1000000 bekomme...

SPID TextData                                 Dur(ms) CPU   Reads   Writes
---- ---------------------------------------- ------- ----- ------- ------
  51 --===== Test for 100 rows ==============       8     0       0      0
  51 --===== Traditional RECURSIVE CTE method      16     0     868      0
  51 --===== Traditional WHILE LOOP method CR      73    16     175      2
  51 --===== Traditional CROSS JOIN table met      11     0      80      0
  51 --===== Itzik's CROSS JOINED CTE method        6     0      63      0
  51 --===== Housekeeping   DROP TABLE #Tally      35    31     401      0

  51 --===== Test for 1000 rows =============       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method      47    47    8074      0
  51 --===== Traditional WHILE LOOP method CR      80    78    1085      0
  51 --===== Traditional CROSS JOIN table met       5     0      98      0
  51 --===== Itzik's CROSS JOINED CTE method        2     0      83      0
  51 --===== Housekeeping   DROP TABLE #Tally       6    15     426      0

  51 --===== Test for 10000 rows ============       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method     434   344   80230     10
  51 --===== Traditional WHILE LOOP method CR     671   563   10240      9
  51 --===== Traditional CROSS JOIN table met      25    31     302     15
  51 --===== Itzik's CROSS JOINED CTE method       24     0     192     15
  51 --===== Housekeeping   DROP TABLE #Tally       7    15     531      0

  51 --===== Test for 100000 rows ===========       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method    4143  3813  800260    154
  51 --===== Traditional WHILE LOOP method CR    5820  5547  101380    161
  51 --===== Traditional CROSS JOIN table met     160   140     479    211
  51 --===== Itzik's CROSS JOINED CTE method      153   141     276    204
  51 --===== Housekeeping   DROP TABLE #Tally      10    15     761      0

  51 --===== Test for 1000000 rows ==========       0     0       0      0
  51 --===== Traditional RECURSIVE CTE method   41349 37437 8001048   1601
  51 --===== Traditional WHILE LOOP method CR   59138 56141 1012785   1682
  51 --===== Traditional CROSS JOIN table met    1224  1219    2429   2101
  51 --===== Itzik's CROSS JOINED CTE method     1448  1328    1217   2095
  51 --===== Housekeeping   DROP TABLE #Tally       8     0     415      0

Wie Sie sehen können, ist die rekursive CTE-Methode nach der While-Schleife die zweitschlechteste für Dauer und CPU und hat in Form von logischen Lesevorgängen den achtfachen Speicherdruck als die While-Schleife . Es ist RBAR auf Steroiden und sollte um jeden Preis für Berechnungen mit einer einzelnen Zeile vermieden werden, ebenso wie eine While-Schleife vermieden werden sollte. Es gibt Orte, an denen Rekursion sehr wertvoll ist, aber dies gehört nicht dazu .

Als Seitenleiste ist Mr. Denny genau das Richtige ... eine richtig große permanente Zahlen- oder Zähltabelle ist für die meisten Dinge der richtige Weg. Was bedeutet richtig dimensioniert? Nun, die meisten Leute verwenden eine Tally-Tabelle, um Daten zu generieren oder Splits für VARCHAR(8000) durchzuführen. Wenn Sie eine Tally-Tabelle mit 11.000 Zeilen mit dem richtigen gruppierten Index auf "N" erstellen, haben Sie genügend Zeilen, um Daten für mehr als 30 Jahre zu erstellen (ich arbeite ziemlich viel mit Hypotheken, daher ist 30 Jahre eine Schlüsselzahl für mich ) und sicherlich genug, um eine VARCHAR(8000)-Aufteilung zu verarbeiten. Warum ist die „richtige Größenbestimmung“ so wichtig? Wenn die Tally-Tabelle häufig verwendet wird, passt sie problemlos in den Cache, was sie blitzschnell macht, ohne den Speicher stark zu belasten.

Zu guter Letzt weiß jeder, dass es beim Erstellen einer permanenten Tally-Tabelle keine große Rolle spielt, mit welcher Methode Sie sie erstellen, da 1) sie nur einmal erstellt wird und 2) wenn es sich um eine 11.000-Zeile handelt Tabelle, alle Methoden werden "gut genug" laufen. Warum also die ganze Empörung meinerseits, welche Methode ich anwenden soll???

Die Antwort ist, dass einige arme Kerle/Mädchen, die es nicht besser wissen und nur ihre Arbeit erledigen müssen, vielleicht so etwas wie die rekursive CTE-Methode sehen und sich entscheiden, sie für etwas viel Größeres und viel häufiger verwendetes als Bauen zu verwenden eine permanente Tally-Tabelle, und ich versuche, diese Leute, die Server, auf denen ihr Code läuft, und das Unternehmen, dem die Daten auf diesen Servern gehören, zu schützen . Ja... es ist so eine große Sache. Es sollte auch für alle anderen gelten. Lehren Sie den richtigen Weg, Dinge zu tun, anstatt "gut genug". Führen Sie einige Tests durch, bevor Sie etwas aus einem Beitrag oder Buch posten oder verwenden ... das Leben, das Sie retten, kann tatsächlich Ihr eigenes sein, besonders wenn Sie glauben, dass ein rekursiver CTE der richtige Weg für so etwas ist.;-)

Danke fürs Zuhören...