sql >> Database teknologi >  >> RDS >> Sqlserver

Hvilke er mere effektive, CTE eller midlertidige tabeller?

Det kommer an på.

Først og fremmest

Hvad er et almindeligt tabeludtryk?

En (ikke-rekursiv) CTE behandles meget på samme måde som andre konstruktioner, der også kan bruges som inline tabeludtryk i SQL Server. Afledte tabeller, visninger og inline-tabel værdisatte funktioner. Bemærk, at mens BOL siger, at en CTE "kan opfattes som et midlertidigt resultatsæt", er dette en rent logisk beskrivelse. Oftere end ikke er det ikke materialiseret i sig selv.

Hvad er en midlertidig tabel?

Dette er en samling af rækker gemt på datasider i tempdb. Datasiderne kan ligge delvist eller helt i hukommelsen. Derudover kan den midlertidige tabel være indekseret og have kolonnestatistikker.

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;

Eksempel 1

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

Meddelelse i planen ovenfor er der ingen omtale af CTE1. Den får bare direkte adgang til basistabellerne og behandles på samme måde som

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

At omskrive ved at materialisere CTE til en midlertidig midlertidig tabel her ville være massivt kontraproduktivt.

Materialisering af CTE-definitionen af

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

Ville involvere kopiering af omkring 8 GB data til en midlertidig tabel, så er der stadig overhead ved at vælge fra den også.

Eksempel 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 

Ovenstående eksempel tager omkring 4 minutter på min maskine.

Kun 15 rækker af de 1.000.000 tilfældigt genererede værdier matcher prædikatet, men den dyre tabelscanning sker 16 gange for at finde disse.

Dette ville være en god kandidat til at materialisere mellemresultatet. Omskrivningen af ​​den tilsvarende midlertidige tabel 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 

Mellemliggende materialisering af en del af en forespørgsel til en midlertidig tabel kan nogle gange være nyttig, selvom den kun evalueres én gang - når den tillader resten af ​​forespørgslen at blive rekompileret ved at udnytte statistik over det materialiserede resultat. Et eksempel på denne tilgang er i SQL Cat-artiklen When To Break Down Complex Queries.

I nogle tilfælde vil SQL Server bruge en spool til at cache et mellemresultat, f.eks. af en CTE, og undgå at skulle revurdere det undertræ. Dette er diskuteret i (migreret) Connect-elementet. Giv et tip til at fremtvinge mellemliggende materialisering af CTE'er eller afledte tabeller. Der oprettes dog ingen statistik om dette, og selvom antallet af spoolede rækker skulle være meget forskelligt fra det anslåede, er det ikke muligt for den igangværende udførelsesplan at tilpasse sig dynamisk som svar (i hvert fald i nuværende versioner. Adaptive forespørgselsplaner kan blive mulige i fremtiden).



  1. Videregivelse af array til Oracle-procedure fra c#

  2. Hvordan kan jeg indsætte binære fildata i et binært SQL-felt ved hjælp af en simpel insert-sætning?

  3. Returner det aktuelle loginnavn i SQL Server (T-SQL)

  4. VÆLG IND ved hjælp af Oracle