Risposte:
Non sembra che lo facciano, ma questo si applica solo ai CTE nidificati.
Crea due tabelle temporanee:
CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );
CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );
Query 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;
Query 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;
Piani di query:
C'è un sovraccarico, ma la parte non necessaria della query viene eliminata molto presto (durante l'analisi in questo caso; la fase di semplificazione in casi più complessi), quindi il lavoro aggiuntivo è veramente minimo e non contribuisce a costi potenzialmente costosi ottimizzazione.
+1 su Erik, ma volevo aggiungere due cose (che non ha funzionato bene in un commento):
Non è nemmeno necessario esaminare i piani di esecuzione per vedere che vengono ignorati quando non utilizzati. Quanto segue dovrebbe produrre un errore "dividi per 0" ma non è dovuto al fatto che cte2
non è stato selezionato affatto:
;WITH cte1 AS
(
SELECT 1 AS [Bob]
),
cte2 AS (
SELECT 1 / 0 AS [Err]
FROM cte1
)
SELECT *
FROM cte1;
I CTE possono essere ignorati, anche se sono gli unici CTE e anche se sono selezionati, se logicamente tutte le righe sarebbero comunque escluse. Di seguito è riportato un caso in cui Query Optimizer sa in anticipo che nessuna riga può essere restituita dal CTE, quindi non si preoccupa nemmeno di eseguirla:
;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;
Per quanto riguarda le prestazioni, il CTE inutilizzato viene analizzato e compilato (o almeno compilato nel caso seguente), quindi non viene ignorato al 100%, ma il costo dovrebbe essere trascurabile e non vale la pena preoccuparsene.
Quando si esegue solo l'analisi, non si verifica alcun errore:
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
Quando si esegue tutto solo dopo l'esecuzione, c'è un 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()
in una vista da usare in un UDF può restituire lo stesso valore da più chiamate a causa dell'ottimizzatore che lo memorizza nella cache.