Tampilan sebaris memungkinkan Anda untuk memilih dari subquery seolah-olah itu adalah tabel yang berbeda:
SELECT
*
FROM /* Selecting from a query instead of table */
(
SELECT
c1
FROM
t1
WHERE
c1 > 0
) a
WHERE
a.c1 < 50;
Saya telah melihat ini disebut menggunakan istilah yang berbeda: pandangan inline, DENGAN klausa, CTE dan tabel turunan. Bagi saya tampaknya mereka adalah sintaks khusus vendor yang berbeda untuk hal yang sama.
Apakah ini asumsi yang salah? Apakah ada perbedaan teknis / kinerja di antara ini?
oracle
cte
derived-tables
Kshitiz Sharma
sumber
sumber
WITH...
). Anda dapat menulis ulang setiap Derived Table sebagai CTE, tetapi mungkin bukan sebaliknya (misalnya CTE Rekursif atau menggunakan CTE beberapa kali)Jawaban:
Ada beberapa perbedaan penting antara tampilan inline (tabel turunan) dan WITH clause (CTE) di Oracle. Beberapa dari mereka cukup universal, yaitu berlaku untuk RDBMS lainnya.
WITH
dapat digunakan untuk membangun subqueries rekursif, tampilan inline -tidak (sejauh yang saya tahu sama untuk semua RDBMS yang mendukung CTE)WITH
klausa lebih mungkin dieksekusi secara fisik terlebih dahulu; dalam banyak kasus, memilih antaraWITH
tampilan dan inline membuat pengoptimal untuk memilih rencana eksekusi yang berbeda (saya kira itu vendor khusus, mungkin bahkan versi spesifik).WITH
dapat terwujud sebagai tabel sementara (saya tidak tahu apakah ada vendor lain tetapi Oracle mendukung fitur ini).WITH
dapat direferensikan beberapa kali, di subqueries lain, dan di query utama (berlaku untuk sebagian besar RDBMS).sumber
LATERAL
digunakanJawaban 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:
Pertimbangkan kueri berikut yang menggunakan dua tabel turunan:
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:
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: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.
sumber
Untuk SQL Server,
WITH CTE
tentukan himpunan sementara bernama hasil, tetapi hanya diperlukan untuk yang pertamaCTE
. yaituTapi ini bukan subquery, atau subquery yang berhubungan. Ada hal-hal yang dapat Anda lakukan dengan CTE yang tidak dapat Anda lakukan dengan sub-kueri di SQL Server, seperti memperbarui Tabel yang dirujuk dalam CTE. Berikut adalah contoh memperbarui tabel dengan CTE.
Subquery akan seperti itu
Atau sub-kueri yang berkorelasi adalah apa yang Anda berikan dalam OP Anda jika Anda ingin referensi / bergabung / batasi hasil Anda berdasarkan a.c1.
Jadi, mereka jelas bukan hal yang sama, meskipun dalam banyak kasus Anda dapat menggunakan satu atau lebih dari metode ini untuk mencapai hasil yang sama. Itu tergantung apa hasil akhirnya.
sumber
Perbedaan utama antara
with
klausa dan subquery di Oracle adalah bahwa Anda bisa mereferensikan kueri dalam klausa beberapa kali. Anda kemudian dapat melakukan beberapa optimasi dengan itu seperti mengubahnya menjadi tabel temp menggunakanmaterialize
petunjuk. Anda juga bisa melakukan kueri rekursif dengan merujuknya sendiri di dalamwith
klausa. Anda tidak dapat melakukannya dengan tampilan inline.Informasi lebih lanjut dapat ditemukan di sini dan di sini .
sumber
MATERIALIZE
.INLINE
untuk kebalikannya.materialize
petunjuk adalah pilihan yang valid. Saya kadang-kadang perlu menentukannya ketika mengoptimalkan pertanyaan yang sangat kompleks di mana saya tahu mewujudkan CTE akan menguntungkan rencana eksekusi.Anda perlu berhati-hati dengan CTE di SQL server bukan hanya oracle, ada kasus di mana kueri berkinerja lebih buruk ketika menggunakan CTE dibandingkan dengan subqueries, cross apply, dll.
Seperti biasa, penting untuk menguji permintaan apa pun di bawah berbagai kondisi pemuatan untuk menentukan mana yang terbaik.
Mirip dengan @scsimon dengan oracle, terkadang MS SQL server tidak melakukan apa yang Anda harapkan terkait penggunaan indeks.
Jika Anda akan menggunakan data yang sama lebih dari sekali, CTE dapat lebih bermanfaat, jika Anda hanya menggunakannya sekali, seringkali sebuah subquery lebih cepat dalam kumpulan data besar.
mis. pilih * dari (subquery saya) bergabung dengan yang lain ...
sumber