sql >> Database >  >> RDS >> Sqlserver

Wat zijn performantere, CTE- of tijdelijke tabellen?

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



  1. 4 manieren om een ​​lijst met schema's te krijgen in SQL Server Agent (T-SQL)

  2. IntegrityError dubbele sleutelwaarde schendt unieke beperking - django/postgres

  3. SIGN() Voorbeelden in SQL Server

  4. CodeIgniter:kan geen verbinding maken met uw databaseserver met behulp van de opgegeven instellingen Foutbericht