Jawaban lain mencakup perbedaan sintaks dengan cukup baik sehingga saya tidak akan membahasnya. Sebaliknya jawaban ini hanya akan mencakup kinerja di Oracle.
Pengoptimal Oracle dapat memilih untuk mewujudkan hasil CTE ke dalam tabel sementara internal. Ia menggunakan heuristik untuk melakukan ini alih-alih optimasi berbasis biaya. Heuristik adalah sesuatu seperti "Mewujudkan CTE jika itu bukan ekspresi sepele dan CTE direferensikan lebih dari sekali dalam kueri". Ada beberapa pertanyaan dimana materialisasi akan meningkatkan kinerja. Ada beberapa pertanyaan yang materialisasi akan secara dramatis menurunkan kinerja. Contoh berikut ini sedikit dibuat-buat tetapi menggambarkan poin dengan baik:
Pertama-tama buat tabel dengan kunci utama yang berisi bilangan bulat dari 1 hingga 10.000:
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;
Pertimbangkan kueri berikut yang menggunakan dua tabel turunan:
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;
Kami dapat melihat permintaan ini dan dengan cepat menentukan bahwa itu tidak akan mengembalikan baris apa pun. Oracle harus dapat menggunakan indeks untuk menentukan itu juga. Di mesin saya, kueri hampir selesai dengan rencana berikut:
Saya tidak suka mengulang sendiri, jadi mari kita coba pertanyaan yang sama dengan CTE:
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;
Ini rencananya:
Itu rencana yang sangat buruk. Alih-alih menggunakan indeks, Oracle mematerialisasi 10000 X 10000 = 100000000 baris ke tabel temp hanya untuk akhirnya mengembalikan 0 baris. Biaya paket ini sekitar 6 M yang jauh lebih tinggi daripada permintaan lainnya. Kueri membutuhkan waktu 68 detik untuk selesai di mesin saya.
Perhatikan bahwa kueri bisa gagal jika tidak ada cukup memori atau ruang kosong di temp tablespace.
Saya dapat menggunakan INLINE
petunjuk tidak berdokumen untuk melarang pengoptimal dari mewujudkan CTE:
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;
Permintaan itu dapat menggunakan indeks dan selesai hampir secara instan. Biaya permintaan sama dengan sebelumnya, 11. Jadi untuk permintaan kedua, heuristik yang digunakan oleh Oracle menghasilkannya dengan memilih permintaan dengan perkiraan biaya 6 M, bukan permintaan dengan perkiraan biaya 11.
WITH...
). Anda dapat menulis ulang setiap Derived Table sebagai CTE, tetapi mungkin bukan sebaliknya (misalnya CTE Rekursif atau menggunakan CTE beberapa kali)