Dalam pertanyaan SO yang sangat baik ini , perbedaan antara CTE
dan sub-queries
dibahas.
Saya ingin secara khusus bertanya:
Dalam keadaan apa masing-masing berikut ini lebih efisien / lebih cepat?
- CTE
- Sub-Permintaan
- Meja Sementara
- Variabel tabel
Secara tradisional, saya telah menggunakan banyak temp tables
dalam pengembangan stored procedures
- karena mereka tampaknya lebih mudah dibaca daripada banyak sub-pertanyaan yang saling terkait.
Non-recursive CTE
s merangkum set data dengan sangat baik, dan sangat mudah dibaca, tetapi adakah keadaan khusus di mana orang bisa mengatakan mereka akan selalu berkinerja lebih baik? atau apakah harus selalu mengutak-atik pilihan yang berbeda untuk menemukan solusi yang paling efisien?
EDIT
Saya baru-baru ini diberitahu bahwa dalam hal efisiensi, tabel sementara adalah pilihan pertama yang baik karena memiliki histogram terkait yaitu statistik.
Jawaban:
SQL adalah bahasa deklaratif, bukan bahasa prosedural. Artinya, Anda membangun pernyataan SQL untuk menggambarkan hasil yang Anda inginkan. Anda tidak memberi tahu mesin SQL cara melakukan pekerjaan.
Sebagai aturan umum, sebaiknya mesin SQL dan pengoptimal SQL menemukan rencana kueri terbaik. Ada banyak upaya orang-tahun yang dikembangkan untuk mengembangkan mesin SQL, jadi biarkan para insinyur melakukan apa yang mereka tahu bagaimana melakukannya.
Tentu saja, ada situasi di mana rencana kueri tidak optimal. Kemudian Anda ingin menggunakan petunjuk kueri, menyusun ulang kueri, memperbarui statistik, menggunakan tabel sementara, menambahkan indeks, dan sebagainya untuk mendapatkan kinerja yang lebih baik.
Adapun pertanyaan Anda. Secara teori, kinerja CTE dan subkueri harus sama karena keduanya memberikan informasi yang sama kepada pengoptimal kueri. Satu perbedaan adalah bahwa CTE yang digunakan lebih dari satu kali dapat dengan mudah diidentifikasi dan dihitung satu kali. Hasilnya kemudian dapat disimpan dan dibaca beberapa kali. Sayangnya, SQL Server tampaknya tidak mengambil keuntungan dari metode optimasi dasar ini (Anda mungkin menyebut ini penghapusan subquery umum).
Tabel sementara adalah masalah yang berbeda, karena Anda memberikan lebih banyak panduan tentang bagaimana kueri harus dijalankan. Satu perbedaan utama adalah bahwa pengoptimal dapat menggunakan statistik dari tabel sementara untuk membuat rencana kueri. Ini dapat menghasilkan keuntungan kinerja. Juga, jika Anda memiliki CTE (subquery) rumit yang digunakan lebih dari satu kali, maka menyimpannya dalam tabel sementara akan sering memberikan peningkatan kinerja. Permintaan dieksekusi hanya sekali.
Jawaban untuk pertanyaan Anda adalah bahwa Anda perlu bermain-main untuk mendapatkan kinerja yang Anda harapkan, terutama untuk permintaan kompleks yang dijalankan secara teratur. Di dunia yang ideal, optimizer kueri akan menemukan jalur eksekusi yang sempurna. Meskipun sering demikian, Anda mungkin dapat menemukan cara untuk mendapatkan kinerja yang lebih baik.
sumber
Tidak ada aturan. Saya menemukan CTE lebih mudah dibaca, dan menggunakannya kecuali mereka menunjukkan beberapa masalah kinerja, dalam hal ini saya menyelidiki masalah yang sebenarnya daripada menebak bahwa CTE adalah masalahnya dan mencoba untuk menulis ulang menggunakan pendekatan yang berbeda. Biasanya ada lebih banyak masalah daripada cara saya memilih untuk menyatakan secara terbuka maksud saya dengan kueri.
Tentu saja ada kasus ketika Anda dapat menguraikan CTE atau menghapus subqueries dan menggantinya dengan tabel #temp dan mengurangi durasi. Ini dapat disebabkan oleh berbagai hal, seperti statistik basi, ketidakmampuan untuk bahkan mendapatkan statistik yang akurat (misalnya bergabung dengan fungsi bernilai tabel), paralelisme, atau bahkan ketidakmampuan untuk menghasilkan rencana yang optimal karena kompleksitas kueri ( dalam hal ini memecahnya dapat memberikan pengoptimal kesempatan bertarung). Tetapi ada juga kasus di mana I / O yang terlibat dengan membuat tabel #temp dapat melebihi aspek kinerja lainnya yang dapat membuat bentuk rencana tertentu menggunakan CTE menjadi kurang menarik.
Sejujurnya, ada terlalu banyak variabel untuk memberikan jawaban yang "benar" untuk pertanyaan Anda. Tidak ada cara yang dapat diprediksi untuk mengetahui kapan kueri dapat memberi tip dalam mendukung satu pendekatan atau yang lain - cukup ketahui bahwa, secara teori, semantik yang sama untuk CTE atau satu subquery tunggal harus mengeksekusi yang sama persis. Saya pikir pertanyaan Anda akan lebih berharga jika Anda menyajikan beberapa kasus di mana ini tidak benar - mungkin Anda telah menemukan batasan dalam pengoptimal (atau menemukan yang dikenal), atau mungkin bahwa pertanyaan Anda tidak setara secara semantik. atau yang mengandung elemen yang menghalangi optimasi.
Jadi saya sarankan menulis kueri dengan cara yang tampaknya paling alami bagi Anda, dan hanya menyimpang ketika Anda menemukan masalah kinerja aktual yang dimiliki pengoptimal. Secara pribadi saya memberi peringkat mereka CTE, kemudian subquery, dengan tabel #temp menjadi pilihan terakhir.
sumber
link / edit / close / flag
- jika ada suara untuk menutup pertanyaan, Anda akan melihat diclose (n)
manan
mewakili jumlah pengguna yang memilih untuk menutup pertanyaan Anda. Jika Anda mengklik tautan itu, Anda akan melihat alasan para pengguna itu dipilih.#temp dibuat dan CTE tidak.
CTE hanyalah sintaks jadi secara teori itu hanya subquery. Itu dieksekusi. #empaan terwujud. Jadi CTE yang mahal dalam suatu join yang dieksekusi berkali-kali mungkin lebih baik dalam #temp. Di sisi lain jika itu adalah evaluasi yang mudah yang tidak dieksekusi tetapi beberapa kali maka tidak sebanding dengan overhead #temp.
Beberapa orang di SO yang tidak suka variabel tabel tapi saya suka mereka karena terwujud dan lebih cepat untuk membuat daripada #temp. Ada kalanya optimizer kueri lebih baik dengan #temp dibandingkan dengan variabel tabel.
Kemampuan untuk membuat PK pada variabel #temp atau tabel memberi pengoptimal kueri lebih banyak informasi daripada CTE (karena Anda tidak dapat mendeklarasikan PK pada CTE).
sumber
Hanya 2 hal yang saya pikir membuatnya SELALU lebih baik menggunakan # Temp Table daripada CTE adalah:
Anda tidak bisa meletakkan kunci utama pada CTE sehingga data yang diakses oleh CTE harus melewati masing-masing indeks dalam tabel CTE daripada hanya mengakses PK atau Indeks di tabel temp.
Karena Anda tidak dapat menambahkan kendala, indeks, dan kunci utama ke CTE, mereka lebih rentan terhadap bug yang masuk dan data yang buruk.
-Ditunjuki kapan kemarin
Berikut adalah contoh di mana kendala #table dapat mencegah data buruk yang tidak terjadi di CTE
sumber
ALWAYS
agak terlalu jauh tapi terima kasih atas jawabannya. Dalam hal keterbacaan penggunaan CTE bisa menjadi hal yang baik.CHECK
kendala yang merujuk pada beberapa baris / tabel adalah tidak diizinkan). Bisakah Anda memposting contoh di mana CTE menunjukkan bug yang tidak sebanding dengan tabel temp?