Mana yang lebih berkinerja, CTE
atau Temporary Tables
?
Mana yang lebih berkinerja, CTE
atau Temporary Tables
?
Jawaban:
Saya akan mengatakan mereka adalah konsep yang berbeda tetapi tidak terlalu berbeda untuk mengatakan "kapur dan keju".
Tabel temporer baik untuk digunakan kembali atau untuk melakukan beberapa proses lewat pada satu set data.
CTE dapat digunakan untuk mengulang atau sekadar meningkatkan keterbacaan.
Dan, seperti tampilan atau tabel sebaris fungsi nilai juga bisa diperlakukan seperti makro untuk diperluas di kueri utama
Tabel temp adalah tabel lain dengan beberapa aturan seputar cakupan
Saya telah menyimpan procs tempat saya menggunakan keduanya (dan variabel tabel juga)
cte vs temporary tables
jadi IMHO jawaban ini perlu menyoroti kekurangan CTE dengan lebih baik. TL; DR dari jawaban yang ditautkan: CTE tidak boleh digunakan untuk kinerja. . Saya setuju dengan kutipan itu karena saya telah mengalami kelemahan CTE.
Tergantung.
Pertama-tama
Apa itu Ekspresi Tabel Umum?
CTE (non rekursif) diperlakukan sangat mirip dengan konstruksi lain yang juga dapat digunakan sebagai ekspresi tabel sebaris di SQL Server. Tabel turunan, Tampilan, dan fungsi nilai tabel sebaris. Perhatikan bahwa sementara BOL mengatakan bahwa CTE "dapat dianggap sebagai kumpulan hasil sementara" ini adalah deskripsi yang sepenuhnya logis. Lebih sering daripada tidak itu tidak materlialized dengan sendirinya.
Apa itu tabel sementara?
Ini adalah kumpulan baris yang disimpan pada halaman data di tempdb. Halaman data mungkin sebagian atau seluruhnya berada dalam memori. Selain itu, tabel sementara dapat diindeks dan memiliki statistik kolom.
Uji Data
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;
Contoh 1
WITH CTE1 AS
(
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
)
SELECT *
FROM CTE1
WHERE A = 780
Perhatikan pada denah di atas tidak ada penyebutan CTE1. Itu hanya mengakses tabel dasar secara langsung dan diperlakukan sama seperti
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
WHERE A = 780
Menulis ulang dengan mewujudkan CTE menjadi tabel sementara menengah di sini akan menjadi sangat kontraproduktif.
Mewujudkan definisi CTE dari
SELECT A,
ABS(B) AS Abs_B,
F
FROM T
Akan melibatkan penyalinan sekitar 8GB data ke tabel sementara kemudian masih ada biaya tambahan untuk memilih darinya juga.
Contoh 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
Contoh di atas membutuhkan waktu sekitar 4 menit di mesin saya.
Hanya 15 baris dari 1.000.000 nilai yang dihasilkan secara acak yang cocok dengan predikatnya, tetapi pemindaian tabel yang mahal terjadi 16 kali untuk menemukannya.
Ini akan menjadi kandidat yang baik untuk mewujudkan hasil antara. Penulisan ulang tabel suhu yang setara membutuhkan waktu 25 detik.
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
Materialisasi menengah dari bagian kueri menjadi tabel sementara kadang-kadang dapat berguna meskipun hanya dievaluasi sekali - jika memungkinkan sisa kueri untuk dikompilasi ulang dengan memanfaatkan statistik pada hasil yang terwujud. Contoh dari pendekatan ini ada di artikel SQL Cat When To Break Down Complex Queries .
Dalam beberapa keadaan SQL Server akan menggunakan spool untuk menyimpan hasil antara, misalnya dari CTE, dan menghindari keharusan untuk mengevaluasi kembali sub pohon itu. Hal ini dibahas dalam item Connect (bermigrasi) Memberikan petunjuk untuk memaksa perwujudan menengah dari CTE atau tabel turunan . Namun tidak ada statistik yang dibuat mengenai hal ini dan bahkan jika jumlah baris yang di-spool sangat berbeda dari perkiraan tidak mungkin untuk rencana eksekusi yang sedang berjalan untuk secara dinamis beradaptasi sebagai tanggapan (setidaknya dalam versi saat ini. Rencana Kueri Adaptif dapat menjadi mungkin di masa depan).
CTE memiliki kegunaannya - ketika data dalam CTE kecil dan ada peningkatan keterbacaan yang kuat seperti halnya pada tabel rekursif. Namun, kinerjanya tentu tidak lebih baik dari variabel tabel dan ketika seseorang berurusan dengan tabel yang sangat besar, tabel sementara secara signifikan mengungguli CTE. Ini karena Anda tidak dapat menentukan indeks pada CTE dan ketika Anda memiliki data dalam jumlah besar yang memerlukan penggabungan dengan tabel lain (CTE hanya seperti makro). Jika Anda menggabungkan beberapa tabel dengan jutaan baris rekaman di setiap tabel, CTE akan bekerja jauh lebih buruk daripada tabel sementara.
Tabel temp selalu ada di disk - selama CTE Anda dapat disimpan di memori, kemungkinan besar akan lebih cepat (seperti variabel tabel juga).
Tapi sekali lagi, jika pemuatan data CTE Anda (atau variabel tabel temp) menjadi terlalu besar, itu akan disimpan di disk juga, jadi tidak ada manfaat besar.
Secara umum, saya lebih suka CTE daripada tabel temp karena hilang setelah saya menggunakannya. Saya tidak perlu berpikir untuk menjatuhkannya secara eksplisit atau apa pun.
Jadi, tidak ada jawaban yang jelas pada akhirnya, tetapi secara pribadi, saya lebih suka CTE daripada tabel temp.
Jadi kueri yang ditugaskan untuk saya optimalkan ditulis dengan dua CTE di SQL server. Itu memakan waktu 28 detik.
Saya menghabiskan dua menit mengubahnya menjadi tabel temp dan kueri membutuhkan waktu 3 detik
Saya menambahkan indeks ke tabel temp di bidang tempat itu bergabung dan menurunkannya menjadi 2 detik
Tiga menit kerja dan sekarang berjalan 12x lebih cepat dengan menghapus CTE. Saya pribadi tidak akan menggunakan CTE karena lebih sulit untuk di-debug juga.
Hal gilanya adalah CTE hanya digunakan sekali dan masih memberikan indeks pada mereka terbukti 50% lebih cepat.
CTE tidak akan mengambil ruang fisik apa pun. Ini hanya kumpulan hasil yang bisa kita gunakan bergabung.
Tabel temp sementara. Kita dapat membuat indeks, membatasi seperti tabel normal untuk itu kita perlu mendefinisikan semua variabel.
Ruang lingkup tabel temp hanya dalam sesi. EX: Buka dua jendela kueri SQL
create table #temp(empid int,empname varchar)
insert into #temp
select 101,'xxx'
select * from #temp
Jalankan kueri ini di jendela pertama lalu jalankan kueri di bawah ini di jendela kedua Anda dapat menemukan perbedaannya.
select * from #temp
Saya telah menggunakan keduanya tetapi dalam prosedur kompleks besar selalu menemukan tabel temp lebih baik untuk bekerja dengan dan lebih metodis. CTE ada kegunaannya tetapi umumnya dengan data kecil.
Misalnya saya telah membuat sprocs yang kembali dengan hasil penghitungan besar dalam 15 detik namun mengonversi kode ini untuk berjalan dalam CTE dan telah melihatnya berjalan lebih dari 8 menit untuk mencapai hasil yang sama.
Terlambat ke pesta, tapi ...
Lingkungan tempat saya bekerja sangat dibatasi, mendukung beberapa produk vendor dan menyediakan layanan "nilai tambah" seperti pelaporan. Karena batasan kebijakan dan kontrak, saya biasanya tidak diperbolehkan memiliki tabel terpisah / ruang data dan / atau kemampuan untuk membuat kode permanen [ini menjadi sedikit lebih baik, tergantung pada aplikasinya].
IOW, saya biasanya tidak dapat mengembangkan prosedur yang tersimpan atau UDFs atau tabel temp, dll. Saya cukup banyak harus melakukan semuanya melalui antarmuka aplikasi MY (Crystal Reports - tambahkan / tautkan tabel, setel klausa mana dari w / di CR, dll. ). Satu anugrah KECIL adalah Crystal memungkinkan saya untuk menggunakan PERINTAH (serta SQL Expressions). Beberapa hal yang tidak efisien melalui kemampuan tabel tambahkan / tautan biasa dapat dilakukan dengan menentukan Perintah SQL. Saya menggunakan CTE melalui itu dan mendapatkan hasil yang sangat bagus "dari jarak jauh". CTE juga membantu dengan melaporkan pemeliharaan, tidak memerlukan kode tersebut dikembangkan, diserahkan ke DBA untuk mengkompilasi, mengenkripsi, mentransfer, menginstal, dan kemudian memerlukan pengujian beberapa tingkat. Saya dapat melakukan CTE melalui antarmuka lokal.
Sisi bawah penggunaan CTE w / CR adalah, setiap laporan terpisah. Setiap CTE harus dipertahankan untuk setiap laporan. Di mana saya dapat melakukan SPs dan UDFs, saya dapat mengembangkan sesuatu yang dapat digunakan oleh banyak laporan, hanya memerlukan penautan ke SP dan melewati parameter seolah-olah Anda sedang mengerjakan tabel biasa. CR tidak terlalu pandai menangani parameter ke dalam Perintah SQL, sehingga aspek CR / CTE bisa kurang. Dalam kasus tersebut, saya biasanya mencoba untuk menentukan CTE untuk mengembalikan data yang cukup (tetapi tidak SEMUA data), dan kemudian menggunakan kemampuan pemilihan catatan di CR untuk memotong dan memotong itu.
Jadi ... pilihan saya adalah untuk CTE (sampai saya mendapatkan ruang data saya).
Satu kegunaan di mana saya menemukan kinerja CTE yang luar biasa bijaksana adalah ketika saya perlu menggabungkan Query yang relatif kompleks ke beberapa tabel yang masing-masing memiliki beberapa juta baris.
Saya menggunakan CTE untuk terlebih dahulu memilih subset berdasarkan kolom yang diindeks untuk pertama-tama memotong tabel ini menjadi beberapa ribu baris yang relevan masing-masing dan kemudian bergabung dengan CTE ke kueri utama saya. Ini secara eksponensial mengurangi waktu proses kueri saya.
Sementara hasil untuk CTE tidak di-cache dan variabel tabel mungkin merupakan pilihan yang lebih baik, saya sebenarnya hanya ingin mencobanya dan menemukan kesesuaian dengan skenario di atas.
Saya baru saja menguji ini - baik CTE dan non-CTE (di mana kueri diketik untuk setiap contoh serikat pekerja) keduanya membutuhkan waktu ~ 31 detik. CTE membuat kode jauh lebih mudah dibaca - potong dari 241 menjadi 130 baris yang sangat bagus. Tabel suhu di sisi lain memotongnya menjadi 132 baris, dan mengambil LIMA DETIK untuk dijalankan. Tidak bercanda. semua pengujian ini disimpan dalam cache- semua kueri dijalankan beberapa kali sebelumnya.
Dari pengalaman saya di SQL Server, saya menemukan salah satu skenario di mana CTE mengungguli tabel Temp
Saya perlu menggunakan Kumpulan Data (~ 100000) dari Query kompleks hanya SEKALI dalam Prosedur saya yang tersimpan.
Tabel temp menyebabkan overhead pada SQL di mana Prosedur saya berjalan lambat (karena Tabel Temp adalah tabel terwujud nyata yang ada di tempdb dan Bertahan selama masa pakai prosedur saya saat ini)
Di sisi lain, dengan CTE, CTE hanya bertahan hingga kueri berikut ini dijalankan. Jadi, CTE adalah struktur dalam memori yang praktis dengan Cakupan terbatas. CTE tidak menggunakan tempdb secara default.
Ini adalah salah satu skenario di mana CTE benar-benar dapat membantu menyederhanakan kode Anda dan Tabel Suhu Mengungguli. Saya telah Menggunakan 2 CTE, kira-kira
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