Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Кои са по-ефективни, CTE или временни таблици?

Зависи.

Преди всичко

Какво е общ табличен израз?

(нерекурсивният) CTE се третира много подобно на други конструкции, които също могат да се използват като вградени таблични изрази в SQL Server. Функции с извлечени таблици, изгледи и вградени таблици. Имайте предвид, че докато BOL казва, че CTE "може да се разглежда като временен набор от резултати", това е чисто логическо описание. По-често той не е материализиран сам по себе си.

Какво е временна таблица?

Това е колекция от редове, съхранявани на страници с данни в tempdb. Страниците с данни могат да се намират частично или изцяло в паметта. Освен това временната таблица може да бъде индексирана и да има статистически данни за колони.

Тестови данни

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;

Пример 1

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

Забележете, че в плана по-горе не се споменава CTE1. Той просто има директен достъп до базовите таблици и се третира по същия начин като

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

Пренаписването чрез материализиране на CTE в междинна временна таблица тук би било изключително непродуктивно.

Материализиране на дефиницията на CTE на

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

Би включвало копиране на около 8 GB данни във временна таблица, след което все още има допълнителни разходи за избор от нея.

Пример 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 

Горният пример отнема около 4 минути на моята машина.

Само 15 реда от 1 000 000 произволно генерирани стойности съвпадат с предиката, но скъпото сканиране на таблицата се извършва 16 пъти, за да ги открие.

Това би било добър кандидат за материализиране на междинния резултат. Пренаписването на еквивалентната временна таблица отне 25 секунди.

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 

Междинното материализиране на част от заявка във временна таблица понякога може да бъде полезно, дори ако се оценява само веднъж - когато позволява на останалата част от заявката да бъде прекомпилирана, като се възползва от статистиката за материализирания резултат. Пример за този подход е в статията за SQL Cat Кога да разбиете сложни заявки.

При някои обстоятелства SQL Server ще използва пул за кеширане на междинен резултат, напр. на CTE и избягвайте да преоценявате това поддърво. Това се обсъжда в (мигрирания) елемент Свързване Предоставете намек за принудително междинно материализиране на CTE или производни таблици. Въпреки това не се създават статистически данни за това и дори ако броят на буферираните редове трябваше да бъде значително различен от прогнозния, не е възможно планът за изпълнение в ход да се адаптира динамично в отговор (поне в текущите версии. Адаптивните планове за заявки може да станат възможни в бъдещето).



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Брой(*) срещу Брой(1) - SQL Server

  2. Как да шифровате изглед в SQL Server

  3. Възстановяване на база данни на SQL Server (T-SQL)

  4. Бърз и най-добър трик за възстановяване на MDF файлове на SQL Server

  5. Как SESSION_CONTEXT() работи в SQL Server