Hangileri daha performanslı, CTE veya geçici tablolar?


Yanıtlar:


62

Farklı kavramlar olduğunu söyleyebilirim ama "tebeşir ve peynir" demek için çok farklı değil.

  • Bir geçici tablo, yeniden kullanmak veya bir veri kümesinde birden çok işlem geçişi gerçekleştirmek için iyidir.

  • Bir CTE, tekrarlamak veya basitçe okunabilirliği artırmak için kullanılabilir.
    Ve bir görünüm veya satır içi tablo değerli işlev gibi ana sorguda genişletilecek bir makro gibi ele alınabilir

  • Geçici tablo, kapsamla ilgili bazı kurallara sahip başka bir tablodur

Ben hem (ve tablo değişkenleri de) kullandığım procs sakladım


12
Geçici tablolar aynı zamanda bazen gerekli olan Endekslere ve hatta İstatistiklere izin verirken, bir CTE buna izin vermez.
CodeCowboyOrg

9
Bu cevabın CTE'lerin korkunç performansa yol açabileceği gerçeğini yeterince vurgulamadığını düşünüyorum. Genellikle dba.stackexchange'teki bu cevaba başvuruyorum. Sorunuz arama motorumda ikinci sırada geliyorsa, cte vs temporary tablesIMHO bu cevabın CTE'nin dezavantajlarını daha iyi vurgulaması gerekiyor. TL; bağlantılı cevabın DR'si : Performans için asla bir CTE kullanılmamalıdır. . CTE'nin dezavantajlarını yaşadığım için bu alıntıyı kabul ediyorum.
TT.

2
@TT. İlginç.
CTE'lerin

198

Değişir.

Her şeyden önce

Ortak Tablo İfadesi Nedir?

(Özyinelemesiz) bir CTE, SQL Server'da satır içi tablo ifadeleri olarak da kullanılabilen diğer yapılara çok benzer şekilde işlenir. Türetilmiş tablolar, Görünümler ve satır içi tablo değerli fonksiyonlar. BOL'un bir CTE'nin "geçici sonuç kümesi olarak düşünülebileceğini" söylerken, bunun tamamen mantıklı bir açıklama olduğunu unutmayın. Çoğu zaman kendi başına materyallialize edilmez.

Geçici tablo nedir?

Bu, tempdb olarak veri sayfalarında depolanan satırların bir koleksiyonudur. Veri sayfaları kısmen veya tamamen bellekte kalabilir. Ek olarak geçici tablo indekslenebilir ve sütun istatistiklerine sahip olabilir.

Test verisi

CREATE TABLE T(A INT IDENTITY PRIMARY KEY, B INT , F CHAR(8000) NULL);

INSERT INTO T(B)
SELECT TOP (1000000)  0 + CAST(NEWID() AS BINARY(4))
FROM master..spt_values v1,
     master..spt_values v2;

örnek 1

WITH CTE1 AS
(
SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780

Plan 1

Yukarıdaki planda CTE1'den bahsedilmemiştir. Sadece temel tablolara doğrudan erişir ve

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM   T
WHERE  A = 780 

CTE'yi burada geçici bir geçici tablo haline getirerek yeniden yazmak büyük ölçüde karşı üretken olacaktır.

CTE tanımının gerçekleştirilmesi

SELECT A,
       ABS(B) AS Abs_B,
       F
FROM T

Geçici bir tabloya yaklaşık 8GB veri kopyalamayı içerirdi, o zaman hala ondan seçim yapma yükü var.

ÖRNEK 2

WITH CTE2
     AS (SELECT *,
                ROW_NUMBER() OVER (ORDER BY A) AS RN
         FROM   T
         WHERE  B % 100000 = 0)
SELECT *
FROM   CTE2 T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   CTE2 T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Yukarıdaki örnek makinemde yaklaşık 4 dakika sürüyor.

1.000.000 rasgele oluşturulmuş değerlerin yalnızca 15 satırı yüklemle eşleşir, ancak pahalı tablo taraması bunları bulmak için 16 kez gerçekleşir.

resim açıklamasını buraya girin

Bu, ara sonucu gerçekleştirmek için iyi bir aday olacaktır. Eşdeğer sıcaklık tablosu yeniden yazma işlemi 25 saniye sürdü.

INSERT INTO #T
SELECT *,
       ROW_NUMBER() OVER (ORDER BY A) AS RN
FROM   T
WHERE  B % 100000 = 0

SELECT *
FROM   #T T1
       CROSS APPLY (SELECT TOP (1) *
                    FROM   #T T2
                    WHERE  T2.A > T1.A
                    ORDER  BY T2.A) CA 

Plan ile

Bir sorgunun bir kısmının geçici bir tabloya ara maddileştirilmesi, yalnızca bir kez değerlendirilse bile, somutlaştırılmış sonuç üzerindeki istatistiklerden yararlanarak, sorgunun geri kalanının yeniden derlenmesine izin verdiğinde bazen yararlı olabilir. Bu yaklaşımın bir örneği ne zaman karmaşık sorguları yıkmak için SQL Cat makalesinde bulunmaktadır .

Bazı durumlarda SQL Server, örneğin CTE gibi bir ara sonucu önbelleğe almak için bir biriktirme kullanır ve bu alt ağacı yeniden değerlendirmek zorunda kalmaz. Bu, (geçirilmiş) Bağlan öğesinde tartışılmıştır CTE'lerin veya türetilmiş tabloların ara materyalizasyonunu zorlamak için bir ipucu verin . Bununla birlikte, bu konuda herhangi bir istatistik oluşturulmamıştır ve biriktirilen satırların sayısı tahmin edilenden çok farklı olsa bile, devam eden yürütme planının yanıt olarak dinamik olarak uyarlanması mümkün değildir (en azından mevcut sürümlerde. gelecek).


33
Bu asıl soruyu cevaplayan tek cevaptır (hangisinin farkın ne olduğunu veya hangisinin en sevdiğinizi değil daha iyi performansa sahip olduğunu soran) ve bu soruyu doğru bir şekilde cevaplar: "Bağlıdır" doğru cevaptır. Açıklamak için destek verilerinin desteklenmesine yönelik tek cevap da budur, diğerlerinin birçoğu (çok sayıda oyla), herhangi birinin referans veya kanıt olmadan diğerinden daha iyi olduğunu iddia eder ... Açıkça söylemek gerekirse, tüm bu cevaplar da yanlıştır. . Çünkü "O bağlıdır"
Arkaine55

2
Aynı zamanda iyi yazılmış, iyi referanslı bir cevaptır. Ciddi üst çentik.
Dan Williams

50

CTE'nin kullanımları vardır - CTE'deki veriler küçük olduğunda ve özyinelemeli tablolarda olduğu gibi güçlü okunabilirlik iyileştirmesi olduğunda. Bununla birlikte, performansı kesinlikle tablo değişkenlerinden daha iyi değildir ve çok büyük tablolarla uğraşırken geçici tablolar CTE'den önemli ölçüde daha iyi performans gösterir. Bunun nedeni, bir CTE'de endeksleri tanımlayamamanız ve başka bir tabloyla birleştirilmesi gereken büyük miktarda veriye sahip olmanızdır (CTE sadece bir makro gibidir). Her birinde milyonlarca kayıt satırı bulunan birden çok tabloya katılıyorsanız, CTE geçici tablolardan önemli ölçüde daha kötü performans gösterir.


9
Bunu kendi deneyimlerimden gördüm. CTE'ler önemli ölçüde daha yavaş performans gösterir.
goku_da_master

7
CTE'ler de daha yavaş performans gösterir, çünkü sonuçlar önbelleğe alınmaz. CTE'yi her kullandığınızda sorguyu, planı ve her şeyi yeniden çalıştırır.
goku_da_master

1
Ve db motoru, yalnızca her başvuruyu değil, aynı zamanda tüketici sorgusunun her satırı için , ilişkili bir alt sorgu olarak sorguyu yeniden çalıştırmayı seçebilir ... istenmiyorsa her zaman buna dikkat etmelisiniz.
Mike M

Temp tablosu, disk olan ancak dizine eklenme avantajına sahip olan SQL Server'da tempdb'de saklanır ve SQL optimizer, bu durumda belirli sorgularda iyi çalışır. CTE'nin hangi db veya disk alanında depolandığından emin değil (bellek boyutunu aştığında ve IO sayfalaması için kuyruğa girdiğinde), ancak asla büyük miktarda veri ile optimize edilmedi. Bazen daha hızlı yapmak için derleyici seçeneğini (yeniden derleme ile) kullandım
rmehra76

33

Geçici tablolar her zaman disktedir - CTE'niz bellekte tutulabildiği sürece, büyük olasılıkla daha hızlı olacaktır (bir tablo değişkeni gibi).

Ancak yine, CTE'nizin (veya geçici tablo değişkeninin) veri yükü çok büyük olursa, diskte de saklanır, bu yüzden büyük bir faydası olmaz.

Genel olarak, bir CTE'yi geçici tabloya tercih ederim, çünkü kullandıktan sonra gitti. Açıkça veya başka bir şey bırakmayı düşünmem gerekmiyor.

Sonunda net bir cevap yok, ama şahsen CTE'yi geçici tablolara tercih ederim.


2
SQLite ve PostgreSQL durumunda, geçici tablolar vardır otomatik (genellikle bir oturumun sonunda) düştü. Gerçi diğer DBMS hakkında bilmiyorum.
Serrano

1
CTE geçici bir görüntü gibidir. AFAIK verileri depolanmaz, bu nedenle bellekte veya diskte saklanacak hiçbir şey yoktur. Önemli not, CTE'yi her kullandığınızda sorgu tekrar çalışır.
Rob

1
Şahsen bir CTE'nin hız için Temp tablosundan daha iyi çalıştığını hiç görmedim. Ve geçici tablo ile iyi hata ayıklama çok daha kolay
Mark Monforti

7

Bu yüzden optimize etmek için atanan sorgu SQL sunucusunda iki CTE ile yazılmıştır. 28 saniye sürüyordu.

Onları geçici tablolara dönüştürerek iki dakika geçirdim ve sorgu 3 saniye sürdü

Katıldığı alanda geçici tabloya bir indeks ekledim ve 2 saniyeye indirdim

Üç dakika çalışma ve şimdi CTE'yi kaldırarak 12 kat daha hızlı çalışıyor. Ben şahsen CTE'leri kullanmayacağım, onlar da hata ayıklamak için daha zordur.

Çılgınca şey, CTE'lerin hem sadece bir kez kullanıldıkları hem de üzerlerine bir endeks koymanın% 50 daha hızlı olduğu kanıtlandı.


6

CTE herhangi bir fiziksel yer kaplamaz. Bu sadece join kullanabileceğimiz bir sonuç kümesidir.

Geçici tablolar geçicidir. Tüm değişkenleri tanımlamamız gereken normal tablolar gibi dizinler, kısıtlamalar oluşturabiliriz.

Temp tablosunun kapsamı yalnızca oturum içinde. EX: İki SQL sorgu penceresi aç

create table #temp(empid int,empname varchar)
insert into #temp 
select 101,'xxx'

select * from #temp

İlk pencerede bu sorguyu çalıştırın, sonra ikinci pencerede aşağıdaki sorguyu çalıştırın farkı bulabilirsiniz.

select * from #temp

4
>> "Bu sadece birleştirmeyi kullanabileceğimiz bir sonuç kümesidir." -> Bu doğru değil. CTE bir "sonuç kümesi" değil, satır içi koddur. SQL Server sorgu motoru CTE kodunu sorgu metninin bir parçası olarak ayrıştırır ve buna göre bir yürütme planı oluşturur. CTE'nin satır içi olduğu fikri, sunucunun bir "yürütme planını birleştir" oluşturmasına izin verdiği için CTE kullanmanın en büyük avantajıdır
Ronen Ariely

4

Her ikisini de kullandım ama büyük karmaşık prosedürlerde her zaman geçici tablolarla çalışmak daha iyi ve daha metodik bulduk. CTE'lerin kullanımları vardır, ancak genellikle küçük verilerle.

Örneğin, 15 saniyede büyük hesaplamaların sonuçlarıyla geri dönen ancak bu kodu bir CTE'de çalıştırmak için dönüştüren ve aynı sonuçları elde etmek için 8 dakikadan fazla çalıştığını gördüm.


3

Partiye geç, ama ...

Çalıştığım ortam çok kısıtlı, bazı satıcı ürünlerini destekliyor ve raporlama gibi "katma değerli" hizmetler sağlıyor. Politika ve sözleşme sınırlamaları nedeniyle, genellikle ayrı tablo / veri alanı lüksüne ve / veya kalıcı kod oluşturma yeteneğine izin verilmez [uygulamaya bağlı olarak biraz daha iyi olur].

IOW, ben yapamam genellikle vb saklı yordam veya UDF'leri veya geçici tablolar, geliştirmek oldukça fazla (MY uygulama arayüzü üzerinden her şeyi yapmak için Crystal Reports var - ekleme / bağlantı tablolar, set maddeleri gelen CR / W vs. ). Bir KÜÇÜK tasarruf zarafeti Crystal'in COMMANDS (SQL ifadeleri gibi) kullanmamı sağlamasıdır. Normal ekleme / bağlantı tabloları yeteneği ile verimli olmayan bazı şeyler bir SQL Komutu tanımlanarak yapılabilir. CTE'leri bu yöntemle kullanıyorum ve "uzaktan" çok iyi sonuçlar aldım. CTE'ler ayrıca, kodun geliştirilmesini gerektirmeyen, derlemeyi, şifrelemeyi, aktarmayı, yüklemeyi ve daha sonra çok düzeyli sınamayı gerektirecek bir DBA'ya teslim edilmesini gerektirmeyen bakım w / rapor yardımcı olur. CTE'leri yerel arayüz üzerinden yapabilirim.

CRE'li CRE kullanımının aşağı tarafı, her rapor ayrıdır. Her rapor için her bir CTE korunmalıdır. SP'leri ve UDF'leri yapabileceğim yerde, birden çok rapor tarafından kullanılabilecek bir şey geliştirebilirim, normal bir tabloda çalışıyormuş gibi yalnızca SP'ye bağlanma ve parametreleri iletme gerekir. CR, SQL Komutları ile parametrelerin işlenmesinde gerçekten iyi değildir, bu nedenle CR / CTE yönünün yönü eksik olabilir. Bu durumlarda, genellikle yeterli veri (ancak TÜM veri değil) döndürmek için CTE'yi tanımlamaya çalışırım ve daha sonra bunu dilimlemek ve zar atmak için CR'deki kayıt seçim yeteneklerini kullanırım.

Yani ... oyum CTE'ler için (veri alanımı alana kadar).


3

CTE'nin mükemmel performansını akıllıca bulduğum bir kullanım, her biri birkaç milyon satır olan birkaç tabloya nispeten karmaşık bir Sorguya katılmam gerektiğiydi.

CTE'yi ilk önce bu tabloları her biri birkaç bin ilgili satıra indirecek şekilde dizinlenmiş sütunlara dayalı altkümeyi seçmek için kullandım ve sonra CTE'yi ana sorguma kattım. Bu, benim sorgu çalışma süresini katlanarak azalttı.

CTE sonuçları önbelleğe alınmamış olsa da ve tablo değişkenleri daha iyi bir seçim olabilirken, gerçekten sadece denemek istedim ve yukarıdaki senaryoya uygun buldum.


Ayrıca, ben sadece katılmak CTE kullandığımdan beri gerçekten sorguda bir kez CTE yürütmek bu yüzden sonuçları önbelleğe almak bu açıdan büyük bir sorun değildi
satın almalar

1

Bu gerçekten açık uçlu bir sorudur ve hepsi nasıl kullanıldığına ve geçici tablonun türüne (Tablo değişkeni veya geleneksel tablo) bağlıdır.

Geleneksel bir geçici tablo, geçici tabloları yavaşlatan geçici DB'de verileri depolar; ancak tablo değişkenleri değişmez.


1

Ben sadece bu test-CTE ve CTE olmayan (nerede sorgu her sendika örneği için yazılmıştır) her ikisi de ~ 31 saniye sürdü. CTE kodu çok daha okunabilir hale getirdi - 241 ila 130 satırdan çok güzeldi. Sıcaklık tablosu ise 132 satıra indirdi ve beş saniye sürdü. Şaka değil. tüm bu testler önbelleğe alındı ​​- sorguların tümü daha önce birkaç kez çalıştırıldı.


1

SQL Server'daki deneyimimden, CTE'nin Temp tablosundan daha iyi performans gösterdiği senaryolardan birini buldum

Saklı yordamda sadece ONCE karmaşık bir sorgudan bir DataSet (~ 100000) kullanmak gerekiyordu.

  • Temp tablosu SQL'de bir Prosedürümün yavaş performans gösterdiği bir ek yüke neden oluyordu (Temp Tabloları, tempdb ve mevcut yordamımın ömrü boyunca devam eden gerçek materyalize tablolardır)

  • Öte yandan, CTE ile CTE yalnızca aşağıdaki sorgu çalıştırılana kadar devam eder. Dolayısıyla, CTE, sınırlı Kapsam'a sahip kullanışlı bir bellek içi yapıdır. CTE'ler varsayılan olarak tempdb kullanmaz.

Bu, CTE'lerin kodunuzu ve Outperform Temp Tablosunu basitleştirmeye gerçekten yardımcı olabileceği bir senaryodur. 2 CTE kullandım,

WITH CTE1(ID, Name, Display) 
AS (SELECT ID,Name,Display from Table1 where <Some Condition>),
CTE2(ID,Name,<col3>) AS (SELECT ID, Name,<> FROM CTE1 INNER JOIN Table2 <Some Condition>)
SELECT CTE2.ID,CTE2.<col3>
FROM CTE2
GO

1
Cevabınız çok genel gözüküyor ... "CTE'den daha iyi performans gösteren Temp tablosunu" nasıl ölçüyorsunuz? Zaman ölçümleriniz var mı? Bence cevabınızı düzenlemeli ve daha fazla ayrıntı eklemelisiniz.
Il Vic

Evet benim beyanı desteklemek için zaman ölçümleri ve yürütme planı var.
Amardeep Kohli

Sınırlı ayrıcalıklar nedeniyle img planı için img eklenemiyor. Çözüldükten sonra ayrıntıları güncelleyecek
Amardeep Kohli
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.