Відповіді:
Здається, це не так, але це дійсно стосується лише вкладених 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 може повернути одне і те ж значення з декількох викликів завдяки оптимізатору, який кешує його.