Kami telah menemukan masalah yang menarik dengan SQL Server. Pertimbangkan contoh repro berikut:
CREATE TABLE #test (s_guid uniqueidentifier PRIMARY KEY);
INSERT INTO #test (s_guid) VALUES ('7E28EFF8-A80A-45E4-BFE0-C13989D69618');
SELECT s_guid FROM #test
WHERE s_guid = '7E28EFF8-A80A-45E4-BFE0-C13989D69618'
AND s_guid <> NEWID();
DROP TABLE #test;
Mohon lupakan sejenak bahwa s_guid <> NEWID()
kondisinya tampaknya sama sekali tidak berguna - ini hanyalah contoh repro minimal. Karena probabilitas untuk NEWID()
mencocokkan beberapa nilai konstan yang diberikan sangat kecil, itu harus mengevaluasi ke TRUE setiap waktu.
Tapi ternyata tidak. Menjalankan kueri ini biasanya mengembalikan 1 baris, tetapi kadang-kadang (cukup sering, lebih dari 1 kali dari 10) mengembalikan 0 baris. Saya telah mereproduksinya dengan SQL Server 2008 di sistem saya, dan Anda dapat mereproduksi secara on-line dengan biola yang ditautkan di atas (SQL Server 2014).
Melihat rencana eksekusi mengungkapkan bahwa penganalisa kueri rupanya membagi kondisi menjadi s_guid < NEWID() OR s_guid > NEWID()
:
... yang sepenuhnya menjelaskan mengapa kadang-kadang gagal (jika ID yang dihasilkan pertama lebih kecil dan yang kedua lebih besar dari ID yang diberikan).
Apakah SQL Server memungkinkan untuk mengevaluasi A <> B
sebagai A < B OR A > B
, bahkan jika salah satu ekspresi adalah non-deterministik? Jika ya, di mana dokumen itu didokumentasikan? Atau apakah kami menemukan bug?
Menariknya, AND NOT (s_guid = NEWID())
menghasilkan rencana eksekusi yang sama (dan hasil acak yang sama).
Kami menemukan masalah ini ketika pengembang ingin mengecualikan baris tertentu dan digunakan:
s_guid <> ISNULL(@someParameter, NEWID())
sebagai "jalan pintas" untuk:
(@someParameter IS NULL OR s_guid <> @someParameter)
Saya mencari dokumentasi dan / atau konfirmasi bug. Kode tidak semuanya relevan sehingga penyelesaian tidak diperlukan.
sumber
Jawaban:
Ini adalah poin yang agak kontroversial, dan jawabannya adalah "ya" yang memenuhi syarat.
Diskusi terbaik yang saya sadari diberikan sebagai jawaban atas laporan bug Itzik Ben-Gan Connect Bug dengan NEWID dan Table Expressions , yang ditutup karena tidak akan diperbaiki. Connect telah dipensiunkan, jadi tautannya ada ke arsip web. Sayangnya, banyak materi bermanfaat hilang (atau semakin sulit ditemukan) oleh matinya Connect. Pokoknya, kutipan paling berguna dari Jim Hogg dari Microsoft ada:
Salah satu contoh perubahan perilaku dalam hal ini dari waktu ke waktu adalah NULLIF bekerja secara salah dengan fungsi-fungsi non-deterministik seperti RAND () . Ada juga kasus serupa lainnya yang digunakan misalnya
COALESCE
dengan subquery yang dapat menghasilkan hasil yang tidak terduga, dan yang juga sedang ditangani secara bertahap.Jim melanjutkan:
Ini adalah konsekuensi dari normalisasi, yang terjadi sangat awal selama kompilasi permintaan. Kedua ekspresi dikompilasi ke bentuk normal yang sama persis, sehingga rencana eksekusi yang sama dihasilkan.
sumber
Ini didokumentasikan (semacam) di sini:
Fungsi Buatan Pengguna
Ini bukan satu-satunya bentuk kueri tempat rencana kueri akan mengeksekusi NEWID () beberapa kali dan mengubah hasilnya. Ini membingungkan, tetapi sebenarnya penting bagi NEWID () agar berguna untuk pembuatan kunci dan penyortiran acak.
Yang paling membingungkan adalah bahwa tidak semua fungsi non-deterministik benar-benar berperilaku seperti ini. Misalnya RAND () dan GETDATE () akan menjalankan hanya sekali per permintaan.
sumber
=
,,<
dan>
dapat dievaluasi secara efisien terhadap BTree.Untuk apa nilainya, jika Anda melihat dokumen standar SQL 92 lama ini , persyaratan seputar ketidaksetaraan dijelaskan di bagian "
8.2 <comparison predicate>
" sebagai berikut:Catatan: Saya menyertakan 7b dan 7j untuk kelengkapan karena mereka berbicara tentang
<>
perbandingan - Saya tidak berpikir perbandingan konstruktor nilai baris dengan beberapa nilai diimplementasikan dalam T-SQL, kecuali saya hanya salah paham secara besar-besaran tentang apa yang dikatakan ini - yang sangat mungkin dilakukanIni adalah sekelompok sampah yang membingungkan. Tetapi jika Anda ingin terus menyelam sampah ...
Saya pikir 1.ii adalah item yang berlaku dalam skenario ini, karena kami membandingkan nilai "elemen konstruktor nilai baris."
Pada dasarnya itu mengatakan
X <> Y
benar jika nilai yang diwakili oleh X dan Y tidak sama. KarenaX < Y OR X > Y
penulisan ulang yang setara secara logis dari predikat itu, sangat bagus bagi pengoptimal untuk menggunakannya.Standar tidak memberikan batasan pada definisi ini terkait dengan deterministik-ness (atau apa pun, Anda mendapatkannya) elemen konstruktor nilai baris di kedua sisi
<>
operator perbandingan. Adalah tanggung jawab kode pengguna untuk berurusan dengan fakta bahwa ekspresi nilai di satu sisi mungkin non-deterministik.sumber