Yanıtlar:
Öyle görünmüyor, ancak bu gerçekten yalnızca iç içe geçmiş CTE'ler için geçerlidir.
İki geçici tablo oluşturun:
CREATE TABLE #t1 (id INT);
INSERT #t1 ( id )
VALUES ( 1 );
CREATE TABLE #t2 (id INT);
INSERT #t2 ( id )
VALUES ( 1 );
Sorgu 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;
Sorgu 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;
Sorgu planları:
Bir ek yük vardır, ancak sorgunun gereksiz bir kısmı çok erken ortadan kaldırılmıştır (bu durumda ayrıştırma sırasında; daha karmaşık durumlarda basitleştirme aşaması), bu nedenle ek iş gerçekten asgari düzeydedir ve potansiyel olarak pahalı maliyete katkıda bulunmaz optimizasyonu.
Erik'e +1, ancak iki şey eklemek istedim (bir yorumda iyi sonuç vermedi):
Kullanılmadıklarında görmezden gelindiklerini görmek için yürütme planlarına bile bakmanıza gerek yoktur. Aşağıdakiler "0'a böl" hatası vermelidir, fakat cte2
hiçbir şekilde seçilmemesi nedeniyle değildir:
;WITH cte1 AS
(
SELECT 1 AS [Bob]
),
cte2 AS (
SELECT 1 / 0 AS [Err]
FROM cte1
)
SELECT *
FROM cte1;
CTE'ler, yalnızca CTE olsalar ve hatta seçilmiş olsalar bile, mantıksal olarak tüm satırlar hariç tutulursa göz ardı edilebilir. Sorgu en iyi duruma getiricisinin CTE'den hiçbir satır döndürülemeyeceğini önceden bildiği bir durum aşağıdadır; bu nedenle yürütmek için bile uğraşmaz:
;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;
Kullanılmayan CTE, performans ile ilgili olarak ayrıştırılır ve derlenir (veya en azından aşağıdaki durumda derlenir), bu nedenle% 100 göz ardı edilmez, ancak maliyet ihmal edilebilir ve endişelenmeye değer olmayacaktır.
Yalnızca ayrıştırırken hata yok:
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
Her şeyi yürütmenin kısa sürmesi durumunda, bir sorun var:
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()
Bir UDF'de kullanılacak bir görünüme sahip olmanın hilesinin, en iyi duruma getiricinin önbelleğe alması nedeniyle birden fazla çağrıdan aynı değeri döndürebileceğini gördüm .