sql >> Databasteknik >  >> RDS >> Sqlserver

Vilka är mer presterande, CTE eller temporära tabeller?

Det beror på.

Först och främst

Vad är ett vanligt tabelluttryck?

En (icke-rekursiv) CTE behandlas mycket på samma sätt som andra konstruktioner som också kan användas som inline-tabelluttryck i SQL Server. Härledda tabeller, vyer och inline-tabellvärderade funktioner. Observera att även om BOL säger att en CTE "kan ses som en tillfällig resultatuppsättning" är detta en rent logisk beskrivning. Oftast är det inte materialiserat i sin egen rätt.

Vad är en tillfällig tabell?

Detta är en samling rader lagrade på datasidor i tempdb. Datasidorna kan finnas delvis eller helt i minnet. Dessutom kan den temporära tabellen vara indexerad och ha kolumnstatistik.

Testdata

CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);

INSERT INTO T(B)
SELECT TOP (1000000)  0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
     master..spt_values v2;

Exempel 1

WITH CTE1 AS
(
SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780

Observera i planen ovan att det inte nämns något om CTE1. Den kommer bara direkt åt bastabellerna och behandlas på samma sätt som

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM   T
WHERE  A = 780 

Att skriva om genom att materialisera CTE till en mellanliggande temporär tabell här skulle vara enormt kontraproduktivt.

Materialisering av CTE-definitionen av

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T

Skulle innebära att man kopierar ungefär 8 GB data till en tillfällig tabell, då finns det fortfarande överkostnader för att välja från den också.

Exempel 2

WITH CTE2
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY A) AS RN
         FROM   T
         WHERE  B % 100000 = 0)
SELECT *
FROM   CTE2 T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   CTE2 T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Ovanstående exempel tar cirka 4 minuter på min maskin.

Endast 15 rader av de 1 000 000 slumpmässigt genererade värdena matchar predikatet men den dyra tabellskanningen sker 16 gånger för att lokalisera dessa.

Detta skulle vara en bra kandidat för att förverkliga delresultatet. Omskrivningen av motsvarande temptabell tog 25 sekunder.

INSERT INTO #T
SELECT *,
       ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM   T
WHERE  B % 100000 = 0

SELECT *
FROM   #T T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   #T T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Intermediär materialisering av en del av en fråga till en temporär tabell kan ibland vara användbar även om den bara utvärderas en gång - när den gör att resten av frågan kan kompileras om med hjälp av statistik om det materialiserade resultatet. Ett exempel på detta tillvägagångssätt finns i SQL Cat-artikeln When To Break Down Complex Queries.

I vissa fall kommer SQL Server att använda en spool för att cachelagra ett mellanresultat, t.ex. av en CTE, och undvik att behöva omvärdera det underträdet. Detta diskuteras i (migrerad) Connect-objektet. Ge en ledtråd för att tvinga fram mellanliggande materialisering av CTE:er eller härledda tabeller. Men ingen statistik skapas om detta och även om antalet spoolade rader skulle skilja sig mycket från beräknat är det inte möjligt för den pågående exekveringsplanen att dynamiskt anpassa sig som svar (åtminstone i nuvarande versioner. Adaptiva frågeplaner kan bli möjliga i framtiden).



  1. Hur man hämtar data från markören i Oracle med hjälp av For Loop

  2. Minimal loggning med INSERT...VÄLJ i tomma klustrade tabeller

  3. Hantera e-postbekräftelse under registrering i kolv

  4. Vad kan orsaka intermittenta ORA-12519 (TNS:ingen lämplig hanterare hittades) fel