Bir CTE bir sorguda tanımlanır ve hiç kullanılmazsa, ses çıkarır mı?


Yanıtlar:


21

Ö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ı:

FINDIK

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.


28

Erik'e +1, ancak iki şey eklemek istedim (bir yorumda iyi sonuç vermedi):

  1. 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 cte2hiç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;
  2. 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'.
*/

Keşke birden fazla cevabı doğru işaretleyebilseydim, ama Erik seni tabancayla çizdi. :) Ama cevabınız çok bilgilendirici ve aynı zamanda harika, teşekkür ederim!
JD

CTE'ler bir Görünümdeyse ve görünüm 3 kereden fazla iç içe ise? İyileştiricinin vazgeçtiği ve çalıştığı bir nokta yok mu?
Zikato

@ Zikato Hiçbir fikrim yok, ama bu harika bir soru. İlk iki örnekte gösterdiğim sıfır hilesini kullanarak bölmeyi kullanarak bir görünüm oluşturarak çok fazla çaba harcamadan bir test oluşturabilmelisiniz. Lütfen bana bu senaryo hakkında çok merak ettiğim sonuçları bildirin :-).
Solomon Rutzky

@SolomonRutzky Adil olmak gerekirse, test ettim ama net değildi. CTE örneğinizden bir görünüm oluşturdum ve 5 kez iç içe geçirdim, ancak hepsi sürekli tarama ve gerçekten karmaşık olmadığından, optimize edici iyi idare etti. Gelecekte daha ayrıntılı olarak test etmek ve daha karmaşık bir mantığın arkasına gizlemek istiyorum. Seni bilgilendirecegim.
Zikato

@ Zikato İlginç. Neyin "karmaşık" sayılacağından emin değilim, ama evet, örneğim çok basit. "5 kez iç içe" derken, birbirini çağıran diğer görünümlerde / süreçlerde mi, 5 derinlikte mi, alt sorgularda / CTE'lerde olduğunu mu kastediyorsunuz? Yeterli düzeyde yuvalamanın atlayabileceği olasılığı var, ancak referans gösterilmemesi nedeniyle değil, bunun yerine onu kullanmayan ve daha düşük seviyeler için kabul edilen daha yüksek yuva seviyeleri nedeniyle. 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 .
Solomon Rutzky
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.