Hangisi daha ölçülebilir olan, CTE
ya Temporary Tables
?
Hangisi daha ölçülebilir olan, CTE
ya Temporary Tables
?
Yanıtlar:
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
cte vs temporary tables
IMHO 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.
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
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.
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
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).
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.
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.
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ı.
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
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.
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).
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.
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ı.
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