Beeinträchtigen nicht verwendete CTEs in Abfragen die Leistung und / oder ändern sie den generierten Abfrageplan?
Beeinträchtigen nicht verwendete CTEs in Abfragen die Leistung und / oder ändern sie den generierten Abfrageplan?
Dies scheint nicht der Fall zu sein, dies gilt jedoch 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:
Es gibt einen Mehraufwand, aber der unnötige Teil der Abfrage wird sehr früh eliminiert (in diesem Fall während des Parsens; in komplexeren Fällen in der Vereinfachungsphase), sodass der zusätzliche Aufwand wirklich minimal ist und nicht zu potenziell teuren Kosten beiträgt Optimierung.
+1 an Erik, wollte aber zwei Dinge hinzufügen (die in einem Kommentar nicht gut funktionierten):
Sie müssen sich nicht einmal die Ausführungspläne ansehen, um festzustellen, ob sie ignoriert werden, wenn sie nicht verwendet werden. Folgendes sollte den Fehler "Teilen durch 0" verursachen, dies ist jedoch nicht der Fall, da überhaupt cte2
keine Auswahl getroffen wurde:
;WITH cte1 AS
(
SELECT 1 AS [Bob]
),
cte2 AS (
SELECT 1 / 0 AS [Err]
FROM cte1
)
SELECT *
FROM cte1;
CTEs können ignoriert werden, selbst wenn sie der einzige CTE sind, und selbst wenn sie ausgewählt werden, wenn logischerweise alle Zeilen sowieso ausgeschlossen würden. Im folgenden Fall weiß das Abfrageoptimierungsprogramm im Voraus, dass keine Zeilen vom CTE zurückgegeben werden konnten, sodass es sich nicht einmal darum kümmert, sie 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. Die Kosten müssten jedoch vernachlässigbar und nicht besorgniserregend sein.
Wenn nur geparst 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 alles nur kurz vor der Ausführung ausgeführt wird, 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'.
*/
NEWID()
einer Ansicht zur Verwendung in einer UDF den gleichen Wert aus mehreren Aufrufen zurückgeben kann, da das Optimierungsprogramm sie zwischenspeichert.