Apa perbedaan antara CTE dan Tabel Temp?


174

Apa perbedaan antara Common Table Expression (CTE) dan tabel temp? Dan kapan saya harus menggunakan yang satu?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

Tabel Temp

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable


Jawaban:


200

Ini cukup luas, tetapi saya akan memberi Anda jawaban umum yang saya bisa.

CTE ...

  • Tidak dapat dijelaskan (tetapi dapat menggunakan indeks yang ada pada objek yang direferensikan)
  • Tidak dapat memiliki kendala
  • Pada dasarnya pakai VIEWs
  • Tetap hanya sampai permintaan berikutnya dijalankan
  • Dapat bersifat rekursif
  • Tidak memiliki statistik khusus (mengandalkan statistik pada objek yang mendasarinya)

Tabel #Temp ...

  • Adalah tabel terwujud nyata yang ada di tempdb
  • Dapat diindeks
  • Dapat memiliki kendala
  • Bertahanlah untuk kehidupan CONNECTION saat ini
  • Dapat dirujuk oleh kueri atau sub-prosedur lainnya
  • Memiliki statistik khusus yang dihasilkan oleh mesin

Sejauh kapan harus menggunakan masing-masing, mereka memiliki kasus penggunaan yang sangat berbeda. Jika Anda akan memiliki set hasil yang sangat besar, atau perlu merujuknya lebih dari sekali, taruh dalam #temptabel. Jika perlu rekursif, sekali pakai, atau hanya untuk menyederhanakan sesuatu secara logis, CTElebih disukai.

Juga, CTEsebaiknya jangan pernah digunakan untuk kinerja . Anda hampir tidak akan pernah mempercepat dengan menggunakan CTE, karena, sekali lagi, ini hanya tampilan sekali pakai. Anda dapat melakukan beberapa hal yang rapi dengan mereka tetapi mempercepat permintaan tidak benar-benar salah satunya.


mempercepat
penggabungan

1
Mempercepat banyak pertanyaan menggunakan CTE juga merupakan hal karena dengan CTE Anda dapat menambahkan pengetahuan bisnis Anda sendiri untuk mengungguli pengoptimal kueri. Misalnya, Anda dapat memiliki bagian 1 dari CTE Anda pilih dari tabel di mana Anda tahu bahwa baris yang dihasilkan akan sangat kecil. Di dalam kueri yang sama, Anda dapat bergabung dengan resultset kecil ini ke beberapa resultset lebih besar dan benar-benar mem-bypass masalah yang disebabkan oleh statistik basi dll. Untuk melakukan ini, Anda perlu menambahkan petunjuk kueri untuk memaksa pesanan. Berhasil, ini meningkatkan kinerja.
Dave Hilditch

"tidak pernah digunakan untuk kinerja" adalah pernyataan yang luas dan agak subyektif, meskipun saya mengerti maksud Anda. Meskipun, di samping komentar lain, potensi keuntungan kinerja lain dari menggunakan CTE dapat terjadi ketika beralih ke CTE rekursif dari bentuk rekursi lain seperti panggilan prosedur rekursif atau kursor.
JD

29

SUNTING:

Silakan lihat komentar Martin di bawah ini:

CTE tidak terwujud sebagai tabel dalam memori. Itu hanya cara merangkum definisi permintaan. Dalam kasus OP, itu akan digarisbawahi dan sama dengan hanya melakukan SELECT Column1, Column2, Column3 FROM SomeTable. Sebagian besar waktu mereka tidak terwujud di muka, itulah sebabnya ini tidak mengembalikan baris WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, juga memeriksa rencana eksekusi. Meskipun terkadang ada kemungkinan untuk meretas rencana untuk mendapatkan gulungan. Ada item sambung yang meminta petunjuk untuk ini. - Martin Smith 15 Feb '12 pada 17:08


Jawaban asli

CTE

Baca lebih lanjut tentang MSDN

CTE membuat tabel yang digunakan dalam memori, tetapi hanya valid untuk kueri spesifik yang mengikutinya. Saat menggunakan rekursi, ini bisa menjadi struktur yang efektif.

Anda mungkin juga ingin mempertimbangkan menggunakan variabel tabel. Ini digunakan sebagai tabel temp digunakan dan dapat digunakan beberapa kali tanpa perlu direalisasikan kembali untuk setiap bergabung. Juga, jika Anda perlu bertahan beberapa catatan sekarang, tambahkan beberapa catatan lagi setelah pilih berikutnya, tambahkan beberapa catatan lagi setelah op lain, lalu kembalikan hanya segelintir catatan itu, maka ini bisa menjadi struktur yang berguna, karena tidak perlu dijatuhkan setelah eksekusi. Sebagian besar hanya gula sintaksis. Namun, jika Anda tetap menghitung baris rendah, itu tidak pernah terwujud ke disk. Lihat apa perbedaan antara variabel tabel temp dan tabel dalam SQL Server? untuk lebih jelasnya.

Tabel Temp

Baca lebih lanjut tentang MSDN - Gulir ke bawah sekitar 40% dari jalan

Tabel temp secara harfiah adalah tabel yang dibuat di disk, hanya dalam database tertentu yang semua orang tahu dapat dihapus. Adalah tanggung jawab seorang dev yang baik untuk menghancurkan tabel-tabel itu ketika mereka tidak lagi dibutuhkan, tetapi DBA juga dapat menghapusnya.

Tabel sementara datang dalam dua variasi: Lokal dan global. Dalam hal MS Sql Server Anda menggunakan #tableNamepenunjukan untuk lokal, dan ##tableNamepenunjukan untuk global (perhatikan penggunaan # tunggal atau ganda sebagai karakteristik pengidentifikasi).

Perhatikan bahwa dengan temp tables, sebagai kebalikan dari variabel table atau CTE, Anda dapat menerapkan indeks dan sejenisnya, karena ini adalah tabel yang sah dalam arti kata yang normal.


Secara umum saya akan menggunakan tabel temp untuk kueri yang lebih panjang atau lebih besar, dan variabel CTE atau tabel jika saya sudah memiliki dataset kecil dan ingin dengan cepat membuat skrip sedikit kode untuk sesuatu yang kecil. Pengalaman dan saran orang lain menunjukkan bahwa Anda harus menggunakan CTE di mana Anda memiliki sejumlah kecil baris yang dikembalikan darinya. Jika Anda memiliki jumlah besar, Anda mungkin akan mendapat manfaat dari kemampuan untuk mengindeks pada tabel temp.


11
CTE tidak terwujud sebagai tabel dalam memori. Itu hanya cara merangkum definisi permintaan. Dalam kasus OP, itu akan digarisbawahi dan sama dengan hanya melakukanSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith

4
Sebagian besar waktu mereka tidak terwujud di muka, itulah sebabnya ini tidak mengembalikan baris WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, juga memeriksa rencana eksekusi. Meskipun terkadang ada kemungkinan untuk meretas rencana untuk mendapatkan gulungan. Ada item sambung yang meminta petunjuk untuk ini.
Martin Smith

16

The jawaban yang diterima di sini mengatakan "CTE tidak boleh digunakan untuk kinerja" - tapi itu bisa menyesatkan. Dalam konteks CTE versus tabel temp, saya baru saja selesai menghapus sepotong sampah dari serangkaian procs yang disimpan karena beberapa doofus pasti mengira ada sedikit atau tidak ada overhead untuk menggunakan tabel temp. Saya memasukkan banyak ke dalam CTE, kecuali yang akan secara sah digunakan kembali sepanjang proses. Saya memperoleh kinerja sekitar 20% oleh semua metrik. Saya kemudian mulai menghapus semua kursor yang mencoba menerapkan pemrosesan rekursif. Di sinilah saya melihat keuntungan terbesar. Saya akhirnya memangkas waktu respons dengan faktor sepuluh.

CTE dan tabel temp memiliki kasus penggunaan yang sangat berbeda. Saya hanya ingin menekankan bahwa, meski bukan obat mujarab, pemahaman dan penggunaan CTE yang benar dapat mengarah pada beberapa peningkatan yang benar-benar luar biasa baik dalam kualitas kode / pemeliharaan dan kecepatan. Karena saya punya pegangan pada mereka, saya melihat tabel temporer dan kursor sebagai kejahatan besar pemrosesan SQL. Saya bisa mendapatkan dengan baik dengan variabel tabel dan CTE untuk hampir semuanya sekarang. Kode saya lebih bersih dan lebih cepat.


Sekarang, mari bersikap adil - kursor adalah kejahatan besar ; tabel temp yang paling buruk yang lebih rendah jahat. :-) Ini benar - benar tidak adil untuk menempatkan mereka pada level yang sama, seperti yang Anda lihat sendiri.
RDFozz

@RDFozz benar, neraka memiliki 9 lingkaran seperti yang kita semua tahu . Mari kita meletakkan tabel temp pada 2nd dan kursor pada ... 7? ;)
ypercubeᵀᴹ

1
Anda tahu apa 'kejahatan besar' dalam pemrograman? Ketika orang mengatakan bahwa teknik tertentu itu jahat. Ada tempat untuk kursor. Mereka dapat mengungguli teknik lain dalam skenario tertentu. Tidak ada kejahatan di sini - Anda perlu belajar menggunakan alat yang tepat untuk pekerjaan itu. Ukur apa yang Anda lakukan dan jangan percaya bahwa CTE, Temp Tables, atau Cursors adalah jahat. Ukur - karena kebenaran tergantung pada skenario.
Dave Hilditch

@DaveHilditch itu komentar yang adil, tetapi juga komentar yang adil untuk menyatakan bahwa dalam sangat banyak situasi, kursor bukanlah solusi yang tepat, jadi ini adalah generalisasi yang bisa diterapkan untuk memilikinya, juga hampir merupakan pilihan terakhir.
Mel Padden

1
Dalam pengalaman saya, seorang CURSOR tidak buruk dalam dirinya sendiri. CURSORS umumnya "salah" digunakan oleh pengembang karena di sebagian besar bahasa pemrograman, Anda harus berpikir secara iteratif, sebagai lawan dari SQL di mana Anda sebagian besar harus berpikir dalam kumpulan. Saya tahu ini adalah kesalahan umum di tempat kerja saya di mana Dev hanya tidak bisa "melihat" jalan keluar dari masalah selain dengan CURSOR, jadi mengapa DBA yang baik berguna untuk mengajar dan memperbaikinya. @DaveHilditch sepenuhnya benar: hanya alat yang tepat untuk pekerjaan yang tepat.
Philippe

14

CTE dapat dipanggil berulang kali dalam kueri dan dievaluasi setiap kali direferensikan - proses ini dapat bersifat rekursif. Jika hanya dirujuk sekali maka berperilaku seperti sub-kueri, meskipun CTE dapat parameter.

Tabel sementara secara fisik bertahan, dan mungkin diindeks. Dalam praktiknya, pengoptimal kueri juga dapat bertahan pada hasil gabung menengah atau sub-permintaan di belakang layar, seperti dalam operasi spool, sehingga tidak sepenuhnya benar bahwa hasil CTE tidak pernah bertahan ke disk.

Variabel tabel IIRC (di sisi lain) selalu dalam struktur memori.


4
CTE dapat di-parameterkan? Bagaimana? Juga, variabel tabel tidak selalu dalam struktur memori. Lihat jawaban Martin yang luar biasa untuk pertanyaan terkait.
Paul White

11

Tabel temp adalah objek nyata dalam tempdb, tetapi cte hanyalah sejenis pembungkus di sekitar kueri kompleks untuk menyederhanakan sintaksis rekursi pengorganisasian dalam satu langkah.


8

Alasan utama untuk menggunakan CTE adalah untuk mengakses Fungsi Jendela seperti row_number()dan berbagai fungsi lainnya.

Ini berarti Anda dapat melakukan hal-hal seperti mendapatkan baris pertama atau terakhir per grup SANGAT SANGAT cepat dan efisien - lebih efisien daripada cara lain dalam kebanyakan kasus praktis .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

Anda dapat menjalankan kueri yang mirip dengan yang di atas menggunakan subquery yang berkorelasi atau dengan menggunakan sub-kueri tetapi CTE akan lebih cepat di hampir semua skenario.

Selain itu, CTE sangat membantu menyederhanakan kode Anda. Ini dapat menyebabkan peningkatan kinerja karena Anda lebih memahami kueri dan dapat memperkenalkan lebih banyak logika bisnis untuk membantu pengoptimal menjadi lebih selektif.

Selain itu, CTE dapat meningkatkan kinerja jika Anda memahami logika bisnis Anda dan mengetahui bagian mana dari kueri yang harus dijalankan terlebih dahulu - biasanya, menempatkan kueri paling selektif Anda terlebih dahulu yang mengarah ke set hasil yang dapat menggunakan indeks dalam bergabung berikutnya dan menambahkan option(force order)kueri petunjuk

Akhirnya, CTE tidak menggunakan tempdb secara default sehingga Anda mengurangi pertikaian tentang hambatan itu melalui penggunaannya.

Tabel sementara harus digunakan jika Anda perlu menanyakan data beberapa kali, atau jika Anda mengukur kueri Anda dan menemukan bahwa dengan menyisipkan ke tabel temp dan kemudian menambahkan indeks bahwa kinerja Anda ditingkatkan.


semua poin bagus ... +1
Mel Padden

6

Tampaknya ada sedikit negativitas di sini terhadap CTE.

Pemahaman saya tentang CTE adalah bahwa pada dasarnya semacam pandangan adhoc. SQL adalah bahasa berbasis deklaratif dan himpunan. CTE adalah cara yang bagus untuk mendeklarasikan set! Tidak dapat mengindeks CTE sebenarnya adalah hal yang baik karena Anda tidak perlu melakukannya! Ini benar-benar semacam gula sintaksis untuk membuat kueri lebih mudah dibaca / ditulis. Pengoptimal yang layak akan membuat rencana akses terbaik menggunakan indeks pada tabel yang mendasarinya. Ini berarti Anda dapat secara efektif mempercepat kueri CTE Anda dengan mengikuti saran indeks pada tabel yang mendasarinya.

Selain itu, hanya karena Anda mendefinisikan suatu set sebagai CTE, itu tidak berarti bahwa semua baris dalam set harus diproses. Bergantung pada kueri, pengoptimal mungkin memproses baris "cukup" untuk memenuhi kueri. Mungkin Anda hanya membutuhkan 20 atau lebih pertama untuk layar Anda. Jika Anda membangun tabel temp maka Anda benar-benar perlu membaca / menulis semua baris itu!

Berdasarkan ini saya akan mengatakan bahwa CTE adalah fitur SQL yang hebat dan dapat digunakan di mana saja mereka membuat kueri lebih mudah dibaca. Saya hanya akan berpikir tentang tabel temp untuk proses batch yang benar-benar perlu memproses setiap catatan tunggal. Meski begitu afaik itu tidak benar-benar direkomendasikan karena pada tabel temp jauh lebih sulit bagi database untuk membantu Anda dengan caching dan indeks. Mungkin lebih baik memiliki tabel permanen dengan bidang PK yang unik untuk transaksi Anda.

Saya harus mengakui bahwa pengalaman saya terutama dengan DB2 jadi saya berasumsi bahwa CTE bekerja dengan cara yang sama di kedua produk. Saya dengan senang hati akan dikoreksi jika CTE entah bagaimana lebih rendah di SQL server. ;)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.