CTEがクエリで定義され、使用されない場合、音がしますか?


回答:


21

表示されるようには見えませんが、これは実際にはネストされた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;

クエリプラン:

ナッツ

オーバーヘッドがありますが、クエリの不必要な部分は非常に早い段階で削除されます(この場合は解析中、より複雑な場合は単純化の段階です)。最適化。


28

Erikに+1しましたが、2つのことを追加したかった(コメントではうまくいきませんでした):

  1. 使用されていないときに無視されることを確認するために、実行計画を見る必要さえありません。以下は「0で除算」エラーを生成するはずですがcte2、まったく選択されていないためではありません。

    ;WITH cte1 AS
    (
      SELECT 1 AS [Bob]
    ),
    cte2 AS (
      SELECT 1 / 0 AS [Err]
      FROM cte1
    )
    SELECT *
    FROM   cte1;
  2. 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'.
*/

複数の回答を正解としてマークしたいのですが、エリックはあなたをピストルで引き分けました。:)しかし、あなたの答えは非常に有益であり、素晴らしいです、ありがとう!
JD

CTEがビューにあり、ビューが3回以上ネストされている場合はどうなりますか?オプティマイザがすべてを放棄して実行するポイントはありませんか?
ジカト

@Zikatoわかりませんが、それは素晴らしい質問です。最初の2つの例で示したゼロ除算のトリックを使用してビューを作成することにより、あまり労力をかけずにテストをセットアップできるはずです。このシナリオについて私は今非常に興味があるので、結果を教えてください:-)。
ソロモンラッツキー

@SolomonRutzky公平を期すために、テストしましたが、決定的なものではありませんでした。cteの例からビューを作成し、5回ネストしましたが、それはすべて一定のスキャンであり、それほど複雑ではないため、オプティマイザーは適切に処理しました。将来的にはより徹底的にテストし、より複雑なロジックの背後に隠したいと思います。知らせます。
ジカト

@Zikato興味深い。何が「複雑」と見なされるかはわかりませんが、はい、私の例は非常に単純です。「5回ネストされた」と言うとき、他のビュー/プロシージャが相互に呼び出し、それが5深かったのか、サブクエリ/ CTEだったのか。十分なレベルのネストはそれをスキップする可能性があると思いますが、それが参照されていないためではなく、代わりにそれを使用しないより高いネストレベルとより低いレベルのために想定されているためです。NEWID()UDFで使用するビューを配置するトリックが、オプティマイザーがキャッシュするために、複数の呼び出しから同じ値を返す場所を見てきました。
ソロモンラッツキー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.