Answers:
看来它们并没有,但实际上仅适用于嵌套的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;
查询计划:
有开销,但是查询的不必要部分很早就消除了(在这种情况下是在分析过程中;在更复杂的情况下是简化阶段),因此,额外的工作实际上是最小的,并且不会导致基于成本的潜在昂贵成本优化。
为Erik +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,也可以忽略它们,如果逻辑上所有行都将被排除在外。以下是查询优化器提前知道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 的技巧可以由于优化器将其缓存而从多个调用中返回相同的值。