it-swarm.com.de

Wenn ein CTE in einer Abfrage definiert ist und nie verwendet wird, macht er dann einen Ton?

Beeinträchtigen nicht verwendete CTEs in Abfragen die Leistung und/oder ändern sie den generierten Abfrageplan?

32
J.D.

Es scheint nicht so, aber dies gilt wirklich nur für verschachtelte CTEs.

Erstellen Sie zwei temporäre Tabellen:

CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );

CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );

Abfrage 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;

Abfrage 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;

Abfragepläne:

(NUTS

Es gibt einen Overhead, aber der unnötige Teil der Abfrage wird sehr früh beseitigt (in diesem Fall beim Parsen; in komplexeren Fällen die Vereinfachungsphase), sodass der zusätzliche Aufwand wirklich minimal ist und nicht zu einer potenziell teuren Kostenbasis beiträgt Optimierung.

21
Erik Darling

+1 an Erik, wollte aber zwei Dinge hinzufügen (die in einem Kommentar nicht gut funktionierten):

  1. Sie müssen sich nicht einmal die Ausführungspläne ansehen, um festzustellen, dass sie ignoriert werden, wenn sie nicht verwendet werden. Das Folgende sollte einen Fehler "Teilen durch 0" erzeugen, liegt jedoch nicht an cte2 wird überhaupt nicht ausgewählt:

    ;WITH cte1 AS
    (
      SELECT 1 AS [Bob]
    ),
    cte2 AS (
      SELECT 1 / 0 AS [Err]
      FROM cte1
    )
    SELECT *
    FROM   cte1;
    
  2. CTEs können ignoriert werden, selbst wenn sie die einzigen CTEs sind, und selbst wenn sie ausgewählt sind, if logischerweise würden ohnehin alle Zeilen ausgeschlossen. Das Folgende ist ein Fall, in dem das Abfrageoptimierungsprogramm im Voraus weiß, dass keine Zeilen vom CTE zurückgegeben werden können, sodass es nicht einmal die Mühe macht, es auszuführen:

    ;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;
    

In Bezug auf die Leistung wird der nicht verwendete CTE analysiert und kompiliert (oder zumindest im folgenden Fall kompiliert), sodass er nicht zu 100% ignoriert wird, aber die Kosten müssten vernachlässigbar sein und sollten nicht bedenklich sein.

Wenn nur analysiert wird, gibt es keinen Fehler:

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

Wenn Sie alles kurz vor der Ausführung tun, gibt es ein Problem:

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'.
*/
28
Solomon Rutzky