Яка різниця між CTE та Temp Table?


174

Яка різниця між загальним виразом таблиці (CTE) та тимчасовою таблицею? І коли я повинен використовувати один над іншим?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

Темп. Таблиця

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


Відповіді:


200

Це досить широко, але я дам вам якнайзагальнішу відповідь.

CTEs ...

  • Нерозбірливі (але можуть використовувати наявні індекси на посилаються об'єкти)
  • Не може бути обмежень
  • А по суті , одноразові VIEWs
  • Залишайтеся лише до запуску наступного запиту
  • Може бути рекурсивним
  • Не мають спеціальної статистики (покладайтеся на статистику на базових об'єктах)

# Тематичні таблиці ...

  • Це реальні матеріалізовані таблиці, які існують у tempdb
  • Можна індексувати
  • Може мати обмеження
  • Наполегливі до життя поточного З’єднання
  • На них можуть посилатися інші запити або підпроцедури
  • Мають спеціальні статистичні дані, генеровані двигуном

Що стосується того, коли використовувати кожен, вони мають дуже різні випадки використання. Якщо у вас буде дуже великий набір результатів або вам потрібно буде посилатися на нього не один раз, покладіть його в #tempтаблицю. Якщо воно має бути рекурсивним, одноразовим або просто спростити щось логічно, CTEкращим є.

Крім того , CTEне повинно ніколи бути використано для виконання . Ви майже ніколи не пришвидшите речі, використовуючи CTE, оскільки, знову ж таки, це просто одноразовий вигляд. Ви можете зробити деякі акуратні речі з ними, але прискорення запиту насправді не одна з них.


пришвидшити великий MERGE за допомогою CTE - це річ
AgentFire

1
Пришвидшення багатьох запитів за допомогою CTE також є справою, оскільки за допомогою CTE ви можете додати свої власні знання про бізнес, щоб перевершити оптимізатор запитів. Наприклад, ви можете мати частину 1 вибору CTE з таблиць, де ви знаєте, що отримані рядки будуть дуже маленькими. Всередині того самого запиту ви можете приєднати цей крихітний набір результатів до більшого набору результатів і повністю обійти проблеми, спричинені несвіжою статистикою тощо. Для цього вам потрібно додати підказки запитів, щоб примусити замовлення. Це працює, покращує продуктивність.
Дейв Хілдич

"Ніколи не використовуйся для виконання" - це широке і дещо суб'єктивне твердження, хоча я розумію вашу думку. Хоча, крім інших коментарів, ще один потенційний приріст продуктивності від використання CTE може виникнути при переході на рекурсивний CTE з іншої форми рекурсії, наприклад, рекурсивні виклики процедури або курсор.
JD

29

Редагувати:

Будь ласка, дивіться коментарі Мартіна нижче:

CTE не матеріалізується як таблиця в пам'яті. Це лише спосіб інкапсуляції визначення запиту. У випадку з ОП це буде накреслено і те саме, що робиться SELECT Column1, Column2, Column3 FROM SomeTable. Більшу частину часу вони не матеріалізуються вперед, тому це не повертає рядків WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, а також перевіряйте плани виконання. Хоча іноді вдається зламати план отримання котушки. Є елемент підключення, який вимагає підказки для цього. - Мартін Сміт 15 лютого 1212 о 17:08


Оригінальна відповідь

CTE

Детальніше читайте на MSDN

CTE створює таблицю, яка використовується в пам'яті, але справедлива лише для конкретного запиту, що слідує за нею. При використанні рекурсії це може бути ефективною структурою.

Ви також можете розглянути можливість використання змінної таблиці. Це використовується, оскільки використовується таблиця темпів і може використовуватися кілька разів, не потребуючи повторної матеріалізації для кожного з'єднання. Крім того, якщо вам потрібно зберегти кілька записів зараз, додайте ще кілька записів після наступного вибору, додайте ще кілька записів після іншого оп, а потім поверніть лише ті жменю записів, то це може бути зручною структурою, як це робить Не потрібно скидати їх після виконання. Переважно просто синтаксичний цукор. Однак, якщо тримати кількість рядків низькою, вона ніколи не матеріалізується на диску. Див. У чому різниця між тимчасовою таблицею та змінною таблиці в SQL Server? для отримання детальної інформації.

Темп. Таблиця

Детальніше про MSDN - прокрутіть приблизно 40% шляху

Темп-таблиця - це буквально таблиця, створена на диску, просто в певній базі даних, яку всі знають, може бути видалена. Відповідальність доброго розробника знищує ці таблиці, коли вони більше не потрібні, але DBA також може їх витерти.

Тимчасові столи бувають двох різновидів: локальні та глобальні. З точки зору MS Sql Server, ви використовуєте #tableNameпозначення для локального та ##tableNameпозначення для глобального (зверніть увагу на використання одиничного або подвійного # як ідентифікаційної характеристики).

Зауважте, що для темп-таблиць, на відміну від змінних таблиць або CTE, ви можете застосовувати індекси та подібне, оскільки це законні таблиці в нормальному розумінні цього слова.


Як правило, я використовував би темп-таблиці для більш довгих або великих запитів, а також CTE або змінних таблиць, якщо б у мене вже був невеликий набір даних і я хотів би швидко скриптувати трохи коду для чогось невеликого. Досвід та поради інших людей свідчать про те, що ви повинні використовувати CTE, де ви повертаєте з нього невелику кількість рядків. Якщо у вас є велика кількість, ви, ймовірно, отримаєте користь від можливості індексувати на темп-таблиці.


11
CTE не матеріалізується як таблиця в пам'яті. Це лише спосіб інкапсуляції визначення запиту. У випадку з ОП це буде накреслено і так само, як це робитьсяSELECT Column1, Column2, Column3 FROM SomeTable
Мартін Сміт

4
Більшу частину часу вони не матеріалізуються вперед, тому це не повертає рядків WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, а також перевіряйте плани виконання. Хоча іноді вдається зламати план отримання котушки. Є елемент з'єднання, який вимагає підказки для цього.
Мартін Сміт

16

Тут прийнята відповідь говорить, що "CTE ніколи не слід використовувати для виконання", але це може ввести в оману. У контексті таблиць CTE порівняно з тимчасовими таблицями я щойно закінчив видаляти шматок сміття з набору збережених програм, оскільки деякі doofus, напевно, вважали, що використання темп-таблиць мало або взагалі мало. Я засунув партію в CTE, за винятком тих, які будуть законно використані протягом усього процесу. Я отримав приблизно 20% продуктивності за всіма показниками. Потім я почав видаляти всі курсори, які намагалися здійснити рекурсивну обробку. Тут я побачив найбільший прибуток. Я закінчив скорочення часу реакції в десять разів.

CTE і тимчасові таблиці мають дуже різні випадки використання. Я просто хочу наголосити, що, хоча це не панацея, розуміння та правильне використання CTE можуть призвести до деяких дійсно зоряних поліпшень як якості / ремонту коду, так і швидкості. Оскільки я отримав ручку на них, я бачу тимчасові таблиці та курсори як велике зло в обробці SQL. Я зараз можу отримати чудово за допомогою змінних таблиць та CTE для майже всього зараз. Мій код чистіший і швидший.


Тепер, будьмо справедливими - курсори - велике зло; тимчасові таблиці - в гіршому випадку менше зло. :-) Дійсно несправедливо ставити їх на той самий рівень, як ти сам бачив.
RDFozz

@RDFozz правильно, пекло має 9 кіл, як ми всі знаємо . Дозволяє ставити таблиці темп на 2-у, а курсори на ... 7-й? ;)
ypercubeᵀᴹ

1
Ви знаєте, що таке «велике зло» в програмуванні? Коли люди кажуть, що певна техніка - це зло. Тут є місце для курсорів. Вони можуть перевершити інші методи в певних сценаріях. Тут немає зла - вам потрібно навчитися використовувати правильний інструмент для роботи. Виміряйте, що ви робите, і не вірте шуму, що CTE, Temp Table або Cursors є злими. Міри - бо правда залежить від сценарію.
Дейв Хілдіч

@DaveHilditch - це справедливий коментар, але це також справедливий коментар, який стверджує, що в дуже та дуже багатьох ситуаціях курсори не є правильним рішенням, тому їх можна зробити узагальненим узагальненням, і майже в крайньому випадку.
Мел Падден

1
На мій досвід, КУРСОР сам по собі не поганий. CURSORS зазвичай "неправильно" використовується розробниками, тому що в більшості мов програмування ви повинні думати ітеративно, на відміну від SQL, де вам в основному доводиться мислити партіями. Я знаю, що це звичайна помилка на моєму робочому місці, коли Devs просто не може «побачити» виходу з проблеми, відмінної від CURSOR, тому чому хороша DBA корисна для того, щоб навчити та виправити їх. @DaveHilditch абсолютно прав: правильний інструмент для правильної роботи - це все, що потрібно.
Філіп

14

CTE може викликатися повторно в межах запиту і оцінюється щоразу, коли на нього посилається - цей процес може бути рекурсивним. Якщо на нього просто звертаються один раз, він поводиться так само, як підзапит, хоча CTE можуть бути параметризовані.

Тимчасова таблиця зберігається фізично та може бути індексованою. На практиці оптимізатор запитів також може зберігати результати проміжних з'єднань або підзапитів за лаштунками, як, наприклад, в операціях з випуском, тому не є абсолютно правдивим, що результати CTE ніколи не зберігаються на диску.

Змінні таблиці IIRC (з іншого боку) завжди є структурами пам'яті.


4
ЦТЕ можна параметризувати? Як? Також змінні таблиці не завжди є структурами пам'яті. Дивіться відмінну відповідь Мартіна на пов'язане питання.
Пол Білий

11

Таблиця темпів - це справжній об’єкт у tempdb, але cte є лише своєрідною обгорткою навколо складного запиту для спрощення синтаксису організованої рекурсії за один крок.


8

Основна причина використання CTE - це доступ до функцій вікна, таких як row_number()та різних інших.

Це означає, що ви можете робити такі речі, як отримати перший чи останній ряд у групі ДУЖЕ ДУЖЕ швидко та ефективніше - ефективніше, ніж інші засоби у більшості практичних випадків .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

Ви можете запустити подібний запит до вищевказаного, використовуючи співвіднесений підзапит або за допомогою підзапросу, але CTE буде швидше майже у всіх сценаріях.

Крім того, CTE можуть дійсно допомогти спростити ваш код. Це може призвести до підвищення продуктивності, оскільки ви більше розумієте запит і можете ввести більше ділової логіки, що допоможе оптимізатору бути більш вибірковим.

Крім того, CTE можуть підвищити ефективність, якщо ви розумієте свою бізнес-логіку і знаєте, які частини запиту слід запустити першими - зазвичай, виберіть найперші вибіркові запити, які призводять до наборів результатів, які можуть використовувати індекс при наступному приєднанні та додайте option(force order)запит натяк

Нарешті, CTE не використовують tempdb за замовчуванням, тому ви зменшуєте суперечки щодо цього вузького місця через їх використання.

Тимчасові таблиці слід використовувати, якщо вам потрібно запитувати дані кілька разів, або, якщо ви вимірюєте ваші запити і виявляєте це, вставляючи в таблицю темпів, а потім додаючи індекс, що покращує вашу ефективність.


всі хороші бали ... +1
Мел Падден

6

Здається, тут є трохи негативу щодо CTE.

Моє розуміння CTE полягає в тому, що це в основному своєрідний погляд. SQL є як декларативним, так і мовою на основі набору. CTE - це чудовий спосіб декларування набору! Неможливість індексувати CTE - це насправді гарна річ, тому що вам цього не потрібно! Це дійсно свого роду синтаксичний цукор, щоб полегшити запит для читання / запису. Будь-який гідний оптимізатор розробить найкращий план доступу, використовуючи індекси в базових таблицях. Це означає, що ви могли ефективно пришвидшити запит на CTE, дотримуючись порад щодо індексів в основних таблицях.

Крім того, тільки тому, що ви визначили набір як CTE, це не означає, що всі рядки в наборі повинні бути оброблені. Залежно від запиту оптимізатор може обробити рядки "достатньо", щоб задовольнити запит. Можливо, вам знадобилося лише перші 20 або більше для вашого екрану. Якщо ви створили таблицю темпів, вам дійсно потрібно прочитати / написати всі ці рядки!

Виходячи з цього, я б сказав, що CTE є чудовою особливістю SQL і їх можна використовувати де завгодно, щоб зробити запит простішим для читання. Я б подумав лише про тимчасову таблицю для пакетного процесу, який дійсно потребував би обробляти кожен запис. Навіть тоді afaik це не дуже рекомендується, тому що в темп-таблиці набагато складніше, щоб база даних допомогла вам у кешуванні та індексах. Можливо, краще мати постійну таблицю з унікальним для вашої транзакції ПК ПК.

Я повинен визнати, що мій досвід в основному стосується DB2, тому я припускаю, що CTE працює аналогічно в обох продуктах. Я із задоволенням буду виправленим, якщо CTE якимось чином поступається SQL серверу. ;)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.