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