Heh... förlåt att jag svarar så sent på ett gammalt inlägg. Och, ja, jag var tvungen att svara eftersom det mest populära svaret (vid den tiden, det rekursiva CTE-svaret med länken till 14 olika metoder) i den här tråden är, ummm... prestanda utmanad i bästa fall.
För det första är artikeln med de 14 olika lösningarna bra för att se de olika metoderna för att skapa en siffror/tallytabell i farten, men som påpekats i artikeln och i den citerade tråden finns det en mycket viktigt citat...
"Förslag angående effektivitet och prestanda är ofta subjektiva. Oavsett hur en fråga används, avgör den fysiska implementeringen effektiviteten av en fråga. Därför är det, i stället för att förlita sig på opartiska riktlinjer, absolut nödvändigt att du testar frågan och avgör vilken som ger bäst resultat."
Ironiskt nog innehåller artikeln i sig många subjektiva påståenden och "partiska riktlinjer" såsom "en rekursiv CTE kan generera en nummerlista ganska effektivt " och "Detta är en effektiv metod av att använda WHILE-slingan från ett nyhetsgruppsinlägg av Itzik Ben-Gen" (som jag är säker på att han postade bara i jämförelsesyfte). Kom igen gott folk... Att bara nämna Itziks goda namn kan leda till att någon stackars slarv faktiskt använder den där hemska metoden. Författaren bör öva på vad han predikar och bör göra ett litet prestationstest innan han gör sådana löjligt felaktiga påståenden, särskilt inför eventuell skalbarhet.
Med tanken på att faktiskt göra några tester innan du gör några subjektiva påståenden om vad någon kod gör eller vad någon "gillar", här är en kod du kan göra dina egna tester med. Ställ in profiler för SPID du kör testet från och kolla upp det själv... gör bara en "Search'n'Replace" av numret 1000000 för ditt "favorit" nummer och se...
--===== 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
Medan vi håller på, här är siffrorna jag får från SQL Profiler för värdena 100, 1000, 10000, 100000 och 1000000...
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
Som du kan se är den rekursiva CTE-metoden den näst sämsta bara till While Loop för Duration och CPU och har 8 gånger minnestrycket i form av logiska läsningar än While Loop . Det är RBAR på steroider och bör undvikas, till varje pris, för alla enstaka radberäkningar precis som en While Loop bör undvikas. Det finns platser där rekursion är ganska värdefull men det här ÄR INTE en av dem .
Som en sidobar är Mr. Denny helt på topp... ett permanent nummer- eller taltabell med korrekt storlek är vägen att gå för det mesta. Vad betyder rätt storlek? Tja, de flesta använder en Tally-tabell för att generera datum eller för att göra delningar på VARCHAR(8000). Om du skapar en tabell med 11 000 rader med rätt klustrade index på "N", kommer du att ha tillräckligt många rader för att skapa mer än 30 års datum (jag jobbar med bolån en del så 30 år är ett nyckeltal för mig ) och säkerligen tillräckligt för att hantera en VARCHAR(8000) split. Varför är "rätt storlek" så viktigt? Om Tally-bordet används mycket passar det lätt i cachen vilket gör det blixtrande snabbt utan mycket press på minnet alls.
Sist men inte minst, alla vet att om du skapar en permanent Tally-tabell spelar det ingen större roll vilken metod du använder för att bygga den eftersom 1) den bara kommer att göras en gång och 2) om den är ungefär en 11 000 rad tabell, kommer alla metoder att fungera "tillräckligt bra". Så varför all indigination från min sida om vilken metod jag ska använda???
Svaret är att någon stackars kille/tjej som inte vet bättre och bara behöver få sitt jobb gjort kan se något som den rekursiva CTE-metoden och bestämmer sig för att använda den för något mycket större och mycket mer frekvent använt än att bygga. en permanent Tally-tabell och jag försöker skydda dessa personer, servrarna deras kod körs på och företaget som äger data på dessa servrar . Ja... det är så stor sak. Det borde vara för alla andra också. Lär ut rätt sätt att göra saker istället för "tillräckligt bra". Gör några tester innan du postar eller använder något från ett inlägg eller en bok... livet du räddar kan faktiskt vara ditt eget, särskilt om du tror att en rekursiv CTE är rätt väg att gå för något sådant här.;-)
Tack för att du lyssnade...