Влияет ли неиспользуемый CTE в запросах на производительность и / или изменяет сгенерированный план запроса?
Влияет ли неиспользуемый CTE в запросах на производительность и / или изменяет сгенерированный план запроса?
Похоже, что нет, но это действительно относится только к вложенным CTE.
Создайте две временные таблицы:
CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );
CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );
Запрос 1:
WITH your_mom AS (
SELECT TOP 1 *
FROM #t1 AS t
),
also_your_mom AS (
SELECT TOP 1 *
FROM #t2 AS t
)
SELECT *
FROM your_mom;
Запрос 2:
WITH your_mom AS (
SELECT TOP 1 *
FROM #t1 AS t
),
also_your_mom AS (
SELECT TOP 1 *
FROM #t2 AS t
)
SELECT *
FROM also_your_mom;
Планы запроса:
Это накладные расходы, но ненужная часть запроса устраняется очень рано (во время синтаксического анализа в этом случае; стадия упрощения в более сложных случаях), поэтому дополнительная работа действительно минимальна и не способствует потенциально дорогостоящим затратным затратам. оптимизация.
+1 Эрику, но хотел добавить две вещи (которые не сработали в комментарии):
Вам даже не нужно смотреть на планы выполнения, чтобы увидеть, что они игнорируются, когда не используются. Следующее должно привести к ошибке «делить на 0», но не из-за того, что cte2
вообще не выбрано:
;WITH cte1 AS
(
SELECT 1 AS [Bob]
),
cte2 AS (
SELECT 1 / 0 AS [Err]
FROM cte1
)
SELECT *
FROM cte1;
CTE можно игнорировать, даже если они являются единственным CTE, и даже если они выбраны из, если логически все строки будут исключены в любом случае. Ниже приведен случай, когда оптимизатор запросов заранее знает, что строки не могут быть возвращены из CTE, поэтому он даже не потрудился выполнить его:
;WITH cte AS
(
SELECT 1 / 0 AS [Bob]
)
SELECT TOP (1) [object_id]
FROM sys.objects
UNION ALL
SELECT cte.[Bob]
FROM cte
WHERE 1 = 0;
Что касается производительности, неиспользуемый CTE анализируется и компилируется (или, по крайней мере, компилируется в приведенном ниже случае), поэтому он не игнорируется на 100%, но стоимость должна быть незначительной, и о ней не стоит беспокоиться.
При только парсинге нет ошибки:
SET PARSEONLY ON;
;WITH cte1 AS
(
SELECT obj.[NotHere]
FROM sys.objects obj
)
SELECT TOP (1) so.[name]
FROM sys.objects so
GO
SET PARSEONLY OFF;
GO
При выполнении всего, кроме выполнения, возникает проблема:
GO
SET NOEXEC ON;
GO
;WITH cte1 AS
(
SELECT obj.[NotHere]
FROM sys.objects obj
)
SELECT TOP (1) so.[name]
FROM sys.objects so
GO
SET NOEXEC OFF;
GO
/*
Msg 207, Level 16, State 1, Line XXXXX
Invalid column name 'NotHere'.
*/
NEWID()
использования представления в UDF может возвращать одно и то же значение из нескольких вызовов из-за его кэширования оптимизатором.