Respostas:
Parece que não, mas isso realmente se aplica apenas a CTEs aninhadas.
Crie duas tabelas temporárias:
CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );
CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );
Consulta 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;
Consulta 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;
Planos de consulta:
Existe uma sobrecarga, mas a parte desnecessária da consulta é eliminada muito cedo (durante a análise neste caso; o estágio de simplificação em casos mais complexos), portanto, o trabalho adicional é realmente mínimo e não contribui para custos baseados em custos potencialmente caros. otimização.
+1 a Erik, mas queria adicionar duas coisas (o que não funcionou bem em um comentário):
Você nem precisa examinar os planos de execução para ver se eles são ignorados quando não são usados. O seguinte deve produzir um erro "dividir por 0", mas isso não ocorre por cte2
não ter sido selecionado:
;WITH cte1 AS
(
SELECT 1 AS [Bob]
),
cte2 AS (
SELECT 1 / 0 AS [Err]
FROM cte1
)
SELECT *
FROM cte1;
As CTEs podem ser ignoradas, mesmo que sejam a única CTE, e mesmo se forem selecionadas, se logicamente todas as linhas fossem excluídas de qualquer maneira. A seguir, é apresentado um caso em que o otimizador de consulta sabe antecipadamente que nenhuma linha pode ser retornada do CTE; portanto, nem se preocupa em executá-lo:
;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;
Em relação ao desempenho, o CTE não utilizado é analisado e compilado (ou pelo menos compilado no caso abaixo); portanto, não é 100% ignorado, mas o custo deve ser insignificante e não vale a pena se preocupar.
Ao analisar apenas, não há erro:
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
Ao fazer tudo pouco antes da execução, há um problema:
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()
uma exibição para usar em um UDF pode retornar o mesmo valor de várias chamadas devido ao otimizador que o colocou em cache.