Saya menggunakan fungsi T-SQL di COALESCE
mana argumen pertama tidak akan menjadi nol pada sekitar 95% kali dijalankan. Jika argumen pertama adalah NULL
, argumen kedua adalah proses yang cukup panjang:
SELECT COALESCE(c.FirstName
,(SELECT TOP 1 b.FirstName
FROM TableA a
JOIN TableB b ON .....)
)
Jika, misalnya, c.FirstName = 'John'
apakah SQL Server masih menjalankan sub-kueri?
Saya tahu dengan IIF()
fungsi VB.NET , jika argumen kedua Benar, kode masih membaca argumen ketiga (meskipun tidak akan digunakan).
sumber
CASE
selalu mengevaluasi sirkuit dari kiri ke kanan dan selalu pendek) ).SELECT COALESCE((SELECT CASE WHEN RAND() <= 0.5 THEN 1 END), 1);
- ulangi beberapa kali.NULL
Terkadang Anda akan mendapatkannya . Coba lagi denganISNULL
- Anda tidak akan pernahNULL
...Bagaimana dengan yang ini - seperti yang dilaporkan kepada saya oleh Itzik Ben-Gan, yang diberitahu tentang itu oleh Jaime Lafargue ?
Hasil:
Tentu saja ada penyelesaian yang sepele, tetapi intinya tetap
CASE
saja tidak selalu menjamin evaluasi dari arus pendek ke kanan / hubungan arus pendek. Saya melaporkan bug di sini dan ditutup sebagai "sesuai desain." Paul White kemudian mengajukan item Connect ini , dan ditutup sebagai Fixed. Bukan karena itu diperbaiki sendiri, tetapi karena mereka memperbarui Buku Online dengan deskripsi yang lebih akurat dari skenario di mana agregat dapat mengubah urutan evaluasiCASE
ekspresi. Baru-baru ini saya membuat blog lebih banyak tentang ini di sini .EDIT hanya sebuah tambahan, sementara saya setuju bahwa ini adalah kasus tepi, bahwa sebagian besar waktu Anda dapat mengandalkan evaluasi kiri-ke-kanan dan hubungan arus pendek, dan bahwa ini adalah bug yang bertentangan dengan dokumentasi dan mungkin pada akhirnya akan diperbaiki ( ini tidak pasti - lihat percakapan tindak lanjut di posting blog Bart Duncan untuk mengetahui alasannya), saya harus tidak setuju ketika orang mengatakan bahwa sesuatu selalu benar bahkan jika ada kasus tepi tunggal yang membantahnya. Jika Itzik dan yang lainnya dapat menemukan bug soliter seperti ini, itu membuatnya setidaknya di bidang kemungkinan ada bug lain juga. Dan karena kita tidak tahu sisa dari kueri OP, kita tidak bisa mengatakan dengan pasti bahwa dia akan bergantung pada hubungan arus pendek ini tetapi akhirnya digigit olehnya. Jadi bagi saya, jawaban yang lebih aman adalah:
Meskipun Anda biasanya dapat mengandalkan
CASE
untuk mengevaluasi dari kiri ke kanan dan korsleting, seperti dijelaskan dalam dokumentasi, itu tidak akurat untuk mengatakan bahwa Anda selalu dapat melakukannya. Ada dua kasus yang ditunjukkan pada halaman ini di mana itu tidak benar, dan tidak ada bug yang diperbaiki dalam versi SQL Server yang tersedia untuk umum.EDIT di sini adalah kasus lain (saya harus berhenti melakukan itu) di mana
CASE
ekspresi tidak mengevaluasi dalam urutan yang Anda harapkan, meskipun tidak ada agregat yang terlibat.sumber
CASE
yang diam-diam diperbaikiPandangan saya tentang ini adalah bahwa dokumentasi membuatnya cukup jelas bahwa tujuannya adalah bahwa KASUS harus mengalami hubungan pendek. Seperti yang disebutkan Harun, ada beberapa kasus (ha!) Di mana ini terbukti tidak selalu benar.
Sejauh ini, semua ini telah diakui sebagai bug dan diperbaiki - meskipun belum tentu dalam versi SQL Server Anda dapat membeli dan menambal hari ini (bug pelipatan konstan belum sampai ke Pembaruan Kumulatif AFAIK). Potensi bug terbaru - awalnya dilaporkan oleh Itzik Ben-Gan - belum diselidiki (baik Harun atau saya akan menambahkannya ke Connect segera).
Terkait dengan pertanyaan awal, ada masalah lain dengan KASUS (dan karena itu COALESCE) di mana fungsi efek samping atau sub-kueri digunakan. Mempertimbangkan:
Formulir COALESCE sering mengembalikan NULL, rincian lebih lanjut di https://connect.microsoft.com/SQLServer/feedback/details/546437/coalesce-subquery-1-may-return-null
Masalah yang diperlihatkan dengan transformasi pengoptimal dan pelacakan persamaan ekspresi berarti bahwa tidak mungkin untuk menjamin bahwa CASE akan mengalami hubungan arus pendek dalam semua keadaan. Saya dapat membayangkan kasus-kasus di mana bahkan tidak mungkin untuk memprediksi perilaku dengan memeriksa output rencana acara publik, meskipun saya tidak memiliki repro untuk itu hari ini.
Singkatnya, saya pikir Anda bisa cukup yakin bahwa CASE akan mengalami hubungan pendek secara umum (terutama jika orang yang cukup terampil memeriksa rencana eksekusi, dan bahwa rencana eksekusi 'ditegakkan' dengan panduan atau petunjuk rencana) tetapi jika Anda perlu jaminan mutlak, Anda harus menulis SQL yang tidak termasuk ekspresi sama sekali.
Kurasa bukan urusan yang sangat memuaskan.
sumber
Aku datang di kasus lain di mana
CASE
/COALESCE
lakukan sirkuit tidak singkat. TVF berikut akan meningkatkan pelanggaran PK jika disahkan1
sebagai parameter.Jika dipanggil sebagai berikut
Atau sebagai
Keduanya memberikan hasil
menunjukkan bahwa
SELECT
(atau setidaknya populasi variabel tabel) masih dilakukan dan menimbulkan kesalahan meskipun cabang pernyataan itu tidak boleh dihubungi. Rencana untukCOALESCE
versi di bawah.Penulisan ulang kueri ini muncul untuk menghindari masalah
Yang memberi rencana
sumber
Contoh lain
Kueri
Tidak menunjukkan pembacaan
T2
sama sekali.Pencarian
T2
sedang dalam predikat lulus dan operator tidak pernah dieksekusi. TapiApakah acara itu
T2
dibaca. Meskipun tidak ada nilai dariT2
yang benar-benar dibutuhkan.Tentu saja ini tidak benar-benar mengejutkan tetapi saya pikir layak menambahkan ke repositori contoh counter jika hanya karena menimbulkan masalah apa hubungan pendek bahkan berarti dalam bahasa deklaratif berdasarkan set.
sumber
Saya hanya ingin menyebutkan strategi yang mungkin tidak Anda pertimbangkan. Ini mungkin bukan pertandingan di sini, tetapi kadang-kadang berguna. Lihat apakah modifikasi ini memberi Anda kinerja yang lebih baik:
Cara lain untuk melakukannya adalah ini (pada dasarnya setara, tetapi memungkinkan Anda untuk mengakses lebih banyak kolom dari permintaan lain jika perlu):
Pada dasarnya ini adalah teknik "keras" bergabung dengan tabel tetapi termasuk kondisi kapan setiap baris harus BERGABUNG. Dalam pengalaman saya, ini benar-benar membantu rencana eksekusi.
sumber
Tidak, itu tidak akan terjadi. Itu hanya akan berjalan saatc.FirstName
iniNULL
.Namun, Anda harus mencobanya sendiri. Percobaan. Anda bilang subquery Anda panjang. Tolok ukur. Buat kesimpulan sendiri tentang ini.@ Harun jawaban pada sub-kueri yang dijalankan lebih lengkap.
Namun, saya masih berpikir Anda harus mengerjakan ulang permintaan dan penggunaan Anda
LEFT JOIN
. Sebagian besar waktu, sub kueri dapat dihapus dengan mengerjakan ulang kueri Anda untuk menggunakanLEFT JOIN
s.Masalah dengan menggunakan sub kueri adalah bahwa keseluruhan pernyataan Anda akan berjalan lebih lambat karena sub kueri dijalankan untuk setiap baris di set hasil kueri utama.
sumber
Standar aktual mengatakan bahwa semua klausa KETIKA (serta klausa ELSE) harus diuraikan untuk menentukan tipe data ekspresi secara keseluruhan. Saya benar-benar harus mengeluarkan beberapa catatan lama saya untuk menentukan bagaimana kesalahan ditangani. Tapi begitu saja, 1/0 menggunakan bilangan bulat, jadi saya akan berasumsi bahwa itu kesalahan. Ini kesalahan dengan tipe data integer. Ketika Anda hanya memiliki nol dalam daftar penyatuan, agak sulit untuk menentukan tipe data, dan itu masalah lain.
sumber