回答:
表示されるようには見えませんが、これは実際にはネストされたCTEにのみ適用されます。
2つの一時テーブルを作成します。
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しましたが、2つのことを追加したかった(コメントではうまくいきませんでした):
使用されていないときに無視されることを確認するために、実行計画を見る必要さえありません。以下は「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で使用するビューを配置するトリックが、オプティマイザーがキャッシュするために、複数の呼び出しから同じ値を返す場所を見てきました。