Diğer cevaplar sözdizimi farklılıklarını oldukça iyi kapsıyor, bu yüzden buna girmeyeceğim. Bunun yerine bu cevap sadece Oracle'daki performansı kapsayacaktır.
Oracle optimizer, bir CTE'nin sonuçlarını dahili bir geçici tablo haline getirmeyi seçebilir. Maliyet tabanlı optimizasyon yerine bunu yapmak için bir buluşsal yöntem kullanır. Buluşsal yöntem "Önemsiz bir ifade değilse ve CTE'ye sorguda birden çok kez başvuruluyorsa CTE'yi materyalize edin" gibi bir şeydir. Gerçekleştirmenin performansı artıracağı bazı sorgular vardır. Gerçekleştirmenin performansı önemli ölçüde düşüreceği bazı sorgular vardır. Aşağıdaki örnek biraz anlaşılmıştır, ancak noktayı iyi göstermektedir:
İlk olarak, 1'den 10000'e kadar tamsayılar içeren birincil anahtarlı bir tablo oluşturun:
CREATE TABLE N_10000 (NUM_ID INTEGER NOT NULL, PRIMARY KEY (NUM_ID));
INSERT /*+APPEND */ INTO N_10000
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= 10000
ORDER BY LEVEL;
COMMIT;
Türetilmiş iki tablo kullanan aşağıdaki sorguyu düşünün:
SELECT t1.NUM_ID
FROM
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t1
LEFT OUTER JOIN
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
Bu sorguya bakabilir ve herhangi bir satır döndürmeyeceğini hızlı bir şekilde belirleyebiliriz. Oracle, bunu belirlemek için dizini de kullanabilmelidir. Makinemde sorgu aşağıdaki planla neredeyse anında bitiyor:
Kendimi tekrarlamayı sevmiyorum, bu yüzden aynı sorguyu bir CTE ile deneyelim:
WITH N_10000_CTE AS (
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
İşte plan:
Bu gerçekten kötü bir plan. Dizin kullanmak yerine Oracle, 10000 X 10000 = 100000000 satırı geçici bir tablo halinde yalnızca sonunda 0 satır döndürecek şekilde düzenler. Bu planın maliyeti diğer sorgudan çok daha yüksek olan 6 M civarındadır. Sorgunun makinemde tamamlanması 68 saniye sürdü.
Geçici tablo alanında yeterli bellek veya boş alan yoksa, sorgunun başarısız olabileceğini unutmayın.
Doktorun INLINE
CTE'yi gerçekleştirmesine izin vermemek için belgesiz ipucunu kullanabilirim :
WITH N_10000_CTE AS (
SELECT /*+ INLINE */ n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
Bu sorgu dizini kullanabilir ve neredeyse anında biter. Sorgunun maliyeti önceki 11 ile aynıdır. Dolayısıyla, ikinci sorgu için Oracle tarafından kullanılan buluşsal yöntem, tahmin edilen maliyeti 11 olan bir sorgu yerine tahmini maliyeti 6 M olan bir sorgu seçmesine neden oldu.
WITH...
). Her Türetilmiş Tabloyu bir CTE olarak yeniden yazabilirsiniz, ancak tam