Het hangt ervan af.
Allereerst
Wat is een algemene tabeluitdrukking?
Een (niet recursieve) CTE wordt op dezelfde manier behandeld als andere constructies die ook kunnen worden gebruikt als inline tabelexpressies in SQL Server. Afgeleide tabellen, weergaven en inline tabel gewaardeerde functies. Merk op dat hoewel BOL zegt dat een CTE "kan worden gezien als een tijdelijke resultaatset", dit een puur logische beschrijving is. Vaker wel dan niet wordt het op zichzelf niet gemateraliseerd.
Wat is een tijdelijke tafel?
Dit is een verzameling rijen die zijn opgeslagen op gegevenspagina's in tempdb. De gegevenspagina's kunnen zich gedeeltelijk of volledig in het geheugen bevinden. Bovendien kan de tijdelijke tabel worden geïndexeerd en kolomstatistieken hebben.
Testgegevens
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;
Voorbeeld 1
WITH CTE1 AS
(
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780
Merk op dat in het bovenstaande plan geen melding wordt gemaakt van CTE1. Het geeft rechtstreeks toegang tot de basistabellen en wordt op dezelfde manier behandeld als
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
WHERE A = 780
Herschrijven door de CTE hier te materialiseren in een tijdelijke tijdelijke tabel zou enorm contraproductief zijn.
Het materialiseren van de CTE-definitie van
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
Als je ongeveer 8 GB aan gegevens naar een tijdelijke tabel moet kopiëren, is er nog steeds de overhead om eruit te selecteren.
Voorbeeld 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
Het bovenstaande voorbeeld duurt ongeveer 4 minuten op mijn machine.
Slechts 15 rijen van de 1.000.000 willekeurig gegenereerde waarden komen overeen met het predikaat, maar de dure tabelscan gebeurt 16 keer om deze te lokaliseren.
Dit zou een goede kandidaat zijn om het tussenresultaat te concretiseren. Het herschrijven van de equivalente tijdelijke tabel duurde 25 seconden.
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
Tussentijdse materialisatie van een deel van een query in een tijdelijke tabel kan soms nuttig zijn, zelfs als deze slechts één keer wordt geëvalueerd, wanneer de rest van de query opnieuw kan worden gecompileerd, waarbij gebruik wordt gemaakt van statistieken over het gerealiseerde resultaat. Een voorbeeld van deze aanpak staat in het SQL Cat-artikel When To Break Down Complex Queries.
In sommige gevallen zal SQL Server een spool gebruiken om een tussenresultaat in de cache op te slaan, bijv. van een CTE, en voorkom dat u die subboom opnieuw moet evalueren. Dit wordt besproken in het (gemigreerde) item Connect Geef een hint om tussentijdse materialisatie van CTE's of afgeleide tabellen te forceren. Hierover worden echter geen statistieken gemaakt en zelfs als het aantal in de wachtrij geplaatste rijen enorm zou verschillen van het geschatte aantal, is het niet mogelijk dat het lopende uitvoeringsplan dynamisch wordt aangepast als reactie (tenminste in de huidige versies). de toekomst).