Последнее время стали часто обсуждать временные таблицы, табличные переменные и cte. По этой причине было принято решение вынести это обсуждение в отбельную статью.
Временные таблицы. Производительность (temporal tables)
Существует несколько основных моментов, на которые стоит обратить внимание:
- Перемещение данных во временную таблицу может вызвать большую нагрузку на дисковую подсистему, где она лежит tempdb.
- SQL Server очень плотно работает с tempdb и бывает сложно гарантировать время выполнения запросов, которые активно её используют, так как может быть существенная конкуренция за эту БД
Большим преимуществом временных таблиц является то, что на них можно создавать индексы и статистику. Это может существенно ускорить выполнение запросов.
Табличные переменные. Производительность
Самое большие заблуждение, связанное с табличными переменными это то, что многие полагают, что они всегда располагаются в памяти, но это не так. Табличные переменные, как и временные таблицы в последних версиях SQL Server, располагаются в памяти до того момента, пока размер выборки не станет слишком большим, после чего он непременно будет сброшен в tempdb. Если памяти недостаточно или SQL Server испытывает давление на память, то сброс в tempdb происходит чаще.
На что стоит обратить внимание:
- Табличные переменные не позволяют выполнять DDL операции, поэтому вы не можете создать индексы, для улучшения выполнения запросов. Создание UNIQUE constraint позволяет обойти это ограничение.
- Если вопросы с индексами решить как-то возможно, то отсутствие статистики на табличных переменных никак не побороть. На средних и больших выборка это приведёт к проблемам с производительностью.
Создавайте табличные переменные только на малом объёме данных, где нет необходимости в индексах и статистике. Никогда не пользуйтесь табличными переменными, если выборка может содержать более 1000 строк. Я рекомендую не пользоваться табличными переменными уже начиная с 50-100 строк.
Обобщённое табличное выражение. Производительность (CTE)
CTE — это на самом деле только синтаксический способ разбить запрос, который работает в рамках одного запроса. Внутри SQL Server это похоже на создание VIEW «на лету», к которому можно обратиться несколько раз в рамках одного запроса. Вот когда Microsoft рекомендует использовать CTE:
- Создания рекурсивных запросов. Дополнительные сведения см. в разделе Рекурсивные запросы, использующие обобщенные табличные выражения.
- Замены представлений в тех случаях, когда использование представления не оправдано, то есть тогда, когда нет необходимости сохранять в метаданных базы его определение.
- Группирования по столбцу, производного от скалярного подзапроса выборки или функции, которая недетерминирована или имеет внешний доступ.
- Многократных ссылок на результирующую таблицу из одной и той же инструкции.
Таблицы сравнения
Temp Table | Global Temp Table | Table Variable | CTE |
CREATE TABLE #t (ID INT) | CREATE TABLE ##t (ID INT) | DECLARE @t TABLE (ID INT) | ;WITH CTE_T AS (SELECT ID FROM table) |
Создаётся в tempdb | Создаётся в tempdb | Создаётся в tempdb, но ведёт себя как переменная | Создаётся в памяти, при недостаткте которой, данные помещаются в tempdb |
Доступна только в текущей сессии | Доступна всем сессиям | Доступна только в текущем батче текущей сессии | Доступна только в текущем запросе текущей сесcии |
Доступна пока работает активная сессия | Доступна всем сессиям пока активна сессия, создавшая таблицу | Автоматические уничтожается когда сессия отключается/переходит на другой батч | Автоматически уничтожается, после перехода на другой запрос |
Могут быть созданы: Primary key, индексы, статистика, ограничения | Могут быть созданы: Primary key, индексы, статистика, ограничения | Кластерные и некластерные индексы могут быть созданы с помощью первичного ключа | Не поддерживается |
Может быть изменена после создания | Может быть изменена после создания | Не может быть изменена после создания | Не может быть изменена после создания |
Не может использоваться во VIEW | Не может использоваться во VIEW | Не может использоваться во VIEW | Может использоваться во VIEW |
Используйте для больших объёмов данных | Используйте для больших объёмов данных, но будьте аккуратны с именами, так как невозможно создать 2 одинаковых названия | Используйте для малого набора данных | Используйте для малого набора данных или когда необходима рекурсия |