クエリ内の未使用のCTEはパフォーマンスに影響するか、生成されたクエリプランを変更しますか?
表示されないようですが、これは実際にはネストされた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である場合でも、また、それらが選択される場合でも無視できますif論理的にすべての行が除外されます。以下は、クエリオプティマイザーが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'.
*/