Apakah hubungan pendek klausa SQL WHERE dievaluasi?

142

Apakah ekspresi boolean dalam SQL WHERE klausa hubung singkat dievaluasi ?

Sebagai contoh:

SELECT * 
FROM Table t 
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key) 

Jika @key IS NULL bernilai true, apakah @key TIDAK NULL AND @key = t.Key dievaluasi?

Jika Tidak, mengapa tidak?

Jika Ya, apakah dijamin? Apakah ini bagian dari ANSI SQL atau spesifik database?

Jika basis data spesifik, SqlServer? Peramal? MySQL?

Greg Dean
sumber
Bukankah klausa @key TIDAK NULL berlebihan? Klausa @key IS NULL pada LHS menangani masalah ini?
pemboros
10
@splender - tergantung pada jawaban atas pertanyaan
Greg Dean
@Reg: Saya setuju dengan pemboros. Saya tidak melihat kekurangan atau ada hubungan arus pendek yang membuat perbedaan. Jika @key IS NULL, maka @key = t.Key akan selalu mengembalikan false, seperti NULL! = NULL (karena itu kami menggunakan IS NULL, setelah semua).
Michael Madsen
14
@Michael dan @spender - Maksud pertanyaannya adalah, apakah kondisi kedua mengevaluasi atau tidak. Inti dari pertanyaannya bukan, apakah pernyataan SQL spesifik ini ditulis dalam karakter sesedikit mungkin. Dalam contoh yang lebih rumit tidak diragukan lagi akan menjadi masalah, seolah-olah di mana klausa hubung singkat, Anda dapat menulis ekspresi yang jika tidak akan salah.
Greg Dean
2
Hubungan arus pendek menyiratkan evaluasi kondisi dari kiri ke kanan. Mengingat kondisi seperti WHERE a = 1 AND b = 2itu bisa efisien untuk mesin database untuk menemukan semua baris di mana b = 2 pertama, kemudian filter di mana a = 1. Jika Anda meminta jaminan maka optimizer menjadi tidak berguna.
Salman A

Jawaban:

72

ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf

6.3.3.3 Urutan evaluasi aturan

[...]

Jika prioritasnya tidak ditentukan oleh Format atau oleh tanda kurung, evaluasi ekspresi yang efektif umumnya dilakukan dari kiri ke kanan. Namun, tergantung pada implementasi apakah ekspresi benar-benar dievaluasi dari kiri ke kanan, terutama ketika operan atau operator dapat menyebabkan kondisi dinaikkan atau jika hasil dari ekspresi dapat ditentukan tanpa sepenuhnya mengevaluasi semua bagian dari ekspresi.

Komunitas
sumber
4
Tergantung pada implementasi? Bagus. Senang tahu juga. Setidaknya CASEhubung pendek.
dakab
3
Tidakkah ini berarti evaluasi ekspresi tidak didefinisikan dengan baik? "(0 = 0 ATAU NULL)", selalu NULL jika semua istilah dievaluasi, tetapi selalu benar jika dievaluasi dari kiri ke kanan dan hubung singkat.
user48956
6
SQL adalah bahasa deklaratif, pada dasarnya mengekspresikan logika perhitungan tanpa menjelaskan aliran kontrolnya; yang semacam itu bertentangan dengan gaya imperatif evaluasi hubungan singkat dan konsekuensinya.
Jorge Garcia
Saya belum memikirkannya seperti itu @JorgeGarcia. Saya kira evaluasi hubung singkat secara implisit memaksa pesanan pada operasi. Saya bergulat dengan beberapa kode di mana ini mungkin merupakan akar dari masalah yang halus. Terima kasih atas wawasannya.
Carnot Antonio Romero
58

Dari penjelasan di atas, hubungan arus pendek tidak tersedia.

Jika Anda membutuhkannya, saya sarankan pernyataan Kasus:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1selalu dievaluasi, tetapi hanya satu Expr2dan Expr3akan dievaluasi per baris.

PMc
sumber
3
Itu tergantung pada implementasi RDBMS yang saya asumsikan. Untuk SQL Server setidaknya, ada setidaknya satu pengecualian yang didokumentasikan untuk tidak menunjukkan perilaku ini (yaitu korsleting); cf CASE (Transact-SQL) - Keterangan . Saya mengutip kasus ini dalam jawaban ini yang saya berikan pada pertanyaan Sql - Urutan eksplisit kondisi MANA? .
TT.
1
Ekspresi kasus , bukan pernyataan.
jarlh
19

Saya pikir ini adalah salah satu kasus di mana saya akan menulisnya seolah-olah tidak korsleting, karena tiga alasan.

  1. Karena untuk MSSQL, itu tidak diselesaikan dengan melihat BOL di tempat yang jelas, jadi bagi saya, yang membuatnya ambigu secara kanonik.

  2. karena setidaknya saya tahu kode saya akan berfungsi. Dan yang lebih penting, begitu juga mereka yang datang setelah saya, jadi saya tidak mengatur mereka untuk khawatir melalui pertanyaan yang sama berulang kali.

  3. Saya cukup sering menulis untuk beberapa produk DBMS, dan saya tidak ingin harus mengingat perbedaannya jika saya dapat mengatasinya dengan mudah.

dkretz
sumber
4
Saran bagus. Itu tidak menjawab pertanyaan, tetapi itu adalah sudut pandang pragmatis yang hebat. jadi +1
Greg Dean
12

Saya tidak percaya bahwa hubungan arus pendek di SQL Server (2005) dijamin. SQL Server menjalankan kueri Anda melalui algoritme pengoptimalannya yang memperhitungkan banyak hal (indeks, statistik, ukuran tabel, sumber daya, dll.) Untuk menghasilkan rencana eksekusi yang efektif. Setelah evaluasi ini, Anda tidak dapat mengatakan dengan pasti bahwa logika korsleting Anda dijamin.

Saya mengalami pertanyaan yang sama beberapa waktu yang lalu dan penelitian saya benar-benar tidak memberi saya jawaban yang pasti. Anda dapat menulis kueri kecil untuk memberi Anda rasa pembuktian bahwa itu berfungsi tetapi dapatkah Anda yakin bahwa ketika beban pada basis data Anda meningkat, tabel-tabel tumbuh menjadi lebih besar, dan berbagai hal dioptimalkan dan diubah dalam database, kesimpulan itu akan memegang. Saya tidak bisa dan karena itu berbuat salah di sisi hati-hati dan menggunakan KASUS dalam klausa WHERE untuk memastikan hubungan pendek.

Mehmet Aras
sumber
7

Anda harus mengingat cara kerja database. Dengan kueri parameter, db membuat rencana eksekusi berdasarkan kueri tanpa nilai parameter. Kueri ini digunakan setiap kali kueri dijalankan terlepas dari apa nilai yang sebenarnya disediakan. Apakah hubung-pendek kueri dengan nilai-nilai tertentu tidak akan berpengaruh pada rencana eksekusi.

Logicalmind
sumber
6
itu penting untuk kecepatan eksekusi!
user4951
Hanya karena itulah cara kerjanya saat ini tidak berarti itu tidak dapat diubah. Kita harus memisahkan model / semantik dari implementasi. Rencana pelaksanaan diimplementasikan secara internal untuk mengoptimalkan pelaksanaan kueri ... dan semantik hubung singkat tidak hanya bertentangan dengan sifat deklaratif SQL tetapi juga dapat menghambat optimasi tersebut. Namun, jika semantik evaluasi hubung singkat didukung oleh DBMS, implementasi rencana pelaksanaan akan berubah untuk mendukung semantik tersebut.
Jorge Garcia
3

Saya biasanya menggunakan ini untuk parameter opsional. Apakah ini sama dengan hubungan arus pendek?

SELECT  [blah]
FROM    Emp
WHERE  ((@EmpID = -1) OR (@EmpID = EmpID))

Ini memberi saya opsi untuk lulus -1 atau apa pun untuk menjelaskan pemeriksaan opsional atribut. Kadang-kadang ini melibatkan bergabung di beberapa tabel, atau lebih disukai tampilan.

Sangat praktis, tidak sepenuhnya yakin akan kerja ekstra yang diberikannya pada mesin db.

p.campbell
sumber
2

Untuk SQL Server, saya pikir itu tergantung pada versi tetapi pengalaman saya dengan SQL Server 2000 adalah bahwa ia masih mengevaluasi @key = t.Key bahkan ketika @key adalah nol. Dengan kata lain, itu tidak melakukan hubungan arus pendek yang efisien ketika mengevaluasi klausa WHERE.

Saya telah melihat orang merekomendasikan struktur seperti contoh Anda sebagai cara melakukan kueri fleksibel tempat pengguna dapat memasukkan atau tidak memasukkan berbagai kriteria. Pengamatan saya adalah bahwa Key masih terlibat dalam rencana permintaan ketika @key adalah null dan jika Key diindeks maka itu tidak menggunakan indeks secara efisien.

Jenis permintaan fleksibel dengan beragam kriteria ini mungkin merupakan satu kasus di mana SQL yang dibuat secara dinamis benar-benar cara terbaik. Jika @key adalah null maka Anda sama sekali tidak memasukkannya ke dalam kueri.

tetranz
sumber
2

Baru saja menemukan pertanyaan ini, dan sudah menemukan entri blog ini: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

Server SQL bebas untuk mengoptimalkan kueri di mana saja ia mau, jadi dalam contoh yang diberikan di posting blog, Anda tidak dapat mengandalkan korsleting.

Namun, KASUS tampaknya didokumentasikan untuk mengevaluasi dalam urutan tertulis - periksa komentar dari posting blog itu.

stolsvik
sumber
1

Karakteristik utama dari evaluasi hubung singkat adalah bahwa ia berhenti mengevaluasi ekspresi segera setelah hasilnya dapat ditentukan. Itu berarti bahwa sisa ekspresi dapat diabaikan karena hasilnya akan sama terlepas apakah itu dievaluasi atau tidak.

Operator boolean biner bersifat komutatif, artinya:

a AND b == b AND a
a OR  b == b OR  a
a XOR b == b XOR a

jadi tidak ada jaminan dalam urutan evaluasi. Urutan evaluasi akan ditentukan oleh pengoptimal permintaan.

Dalam bahasa dengan objek mungkin ada situasi di mana Anda dapat menulis ekspresi boolean yang hanya dapat dievaluasi dengan evaluasi hubung singkat. Konstruksi kode sampel Anda sering digunakan dalam bahasa seperti itu (C #, Delphi, VB). Sebagai contoh:

if(someString == null | someString.Length == 0 )
  printf("no text in someString");

Contoh C # ini akan menyebabkan pengecualian jika someString == nullkarena itu akan sepenuhnya dievaluasi. Dalam evaluasi hubung singkat, ini akan bekerja setiap saat.

SQL hanya beroperasi pada variabel skalar (tidak ada objek) yang tidak dapat diinisialisasi, sehingga tidak ada cara untuk menulis ekspresi boolean yang tidak dapat dievaluasi. Jika Anda memiliki beberapa nilai NULL, perbandingan apa pun akan menghasilkan false.

Itu berarti bahwa dalam SQL Anda tidak dapat menulis ekspresi yang dievaluasi secara berbeda tergantung pada penggunaan hubung singkat atau evaluasi penuh.

Jika implementasi SQL menggunakan evaluasi hubung singkat, diharapkan hanya dapat mempercepat eksekusi permintaan.

zendar
sumber
1
Ya, operator boolean bersifat komutatif. Saya tidak berpikir benda (atau tidak) ada hubungannya dengan itu.
Greg Dean
1

saya tidak tahu tentang hubungan pendek, tetapi saya akan menuliskannya sebagai pernyataan if-else

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE t.Key=@key

end

juga, variabel harus selalu berada di sisi kanan persamaan. ini membuatnya masuk akal.

http://en.wikipedia.org/wiki/Sargable

DForck42
sumber
1
Adakah yang bisa membenarkannya tentang variabel di sebelah kanan? Untuk beberapa alasan saya sulit mempercayainya.
Greg Dean
searchoracle.techtarget.com/expert/KnowledgebaseAnswer/… tidak dapat menemukan hal lain sekarang
DForck42
Seperti yang saya pahami artikelnya. Ini berbicara tentang fungsi pada nama kolom yang tidak terlalu mahal. Yang saya mengerti. Namun saya tidak berpikir (A = @a) atau (@a = A) penting.
Greg Dean
saya mungkin salah. mungkin pertanyaan yang bagus jika belum ada.
DForck42
1

Di bawah tes cepat dan kotor pada SQL Server 2008 R2:

SELECT *
FROM table
WHERE 1=0
AND (function call to complex operation)

Ini segera kembali tanpa catatan. Jenis perilaku hubung singkat hadir.

Kemudian coba ini:

SELECT *
FROM table
WHERE (a field from table) < 0
AND (function call to complex operation)

mengetahui tidak ada catatan akan memenuhi kondisi ini:

(a field from table) < 0

Ini memakan waktu beberapa detik, menunjukkan perilaku hubung singkat tidak ada lagi dan operasi kompleks sedang dievaluasi untuk setiap catatan.

Semoga ini bisa membantu kalian.

Jorge
sumber
1
Dugaan saya adalah bahwa permintaan pertama adalah "hubung singkat" dalam waktu kompilasi, sebelum eksekusi rencana benar-benar dimulai.
Louis Somers
1

Berikut ini adalah demo untuk membuktikan bahwa MySQL melakukan hubung singkat klausa WHERE :

http://rextester.com/GVE4880

Ini menjalankan kueri berikut:

SELECT myint FROM mytable WHERE myint >= 3 OR myslowfunction('query #1', myint) = 1;
SELECT myint FROM mytable WHERE myslowfunction('query #2', myint) = 1 OR myint >= 3;

Satu-satunya perbedaan antara ini adalah urutan operan dalam kondisi OR.

myslowfunctionsengaja tidur sebentar dan memiliki efek samping menambahkan entri ke tabel log setiap kali dijalankan. Berikut adalah hasil dari apa yang dicatat ketika menjalankan dua pertanyaan di atas:

myslowfunction called for query #1 with value 1
myslowfunction called for query #1 with value 2
myslowfunction called for query #2 with value 1
myslowfunction called for query #2 with value 2
myslowfunction called for query #2 with value 3
myslowfunction called for query #2 with value 4

Di atas menunjukkan bahwa fungsi lambat dieksekusi lebih sering ketika muncul di sisi kiri kondisi ATAU ketika operan lain tidak selalu benar (karena hubungan arus pendek).

Steve Chambers
sumber
4
Hmm apa yang mungkin ingin Anda katakan "Ini adalah demo untuk membuktikan bahwa MySQL memang melakukan hubungan pendek klausa WHERE dalam contoh khusus ini :"
TT.
1
Tentu - itu hanya bukti bahwa itu bisa terjadi.
Steve Chambers
0

Ini membutuhkan tambahan 4 detik dalam penganalisis kueri, jadi dari apa yang saya lihat JIKA bahkan tidak disingkat ...

SET @ADate = NULL

IF (@ADate IS NOT NULL)
BEGIN
    INSERT INTO #ABla VALUES (1)
        (SELECT bla from a huge view)
END

Alangkah baiknya memiliki cara yang terjamin!

kebiruan
sumber
-2

Sangat jelas bahwa server MS Sql mendukung teori hubung singkat, untuk meningkatkan kinerja dengan menghindari pemeriksaan yang tidak perlu,

Contoh Pendukung:

SELECT 'TEST'
WHERE 1 = 'A'

SELECT 'TEST'
WHERE 1 = 1 OR 1 = 'A'

Di sini, contoh pertama akan menghasilkan kesalahan 'Konversi gagal saat mengubah nilai varchar' A 'ke int tipe data.'

Sedangkan yang kedua berjalan dengan mudah karena kondisi 1 = 1 dievaluasi ke TRUE dan dengan demikian kondisi kedua tidak berjalan sama sekali.

Lebih jauh lagi

SELECT 'TEST'
WHERE 1 = 0 OR 1 = 'A'

di sini kondisi pertama akan dinilai false dan karenanya DBMS akan pergi untuk kondisi kedua dan sekali lagi Anda akan mendapatkan kesalahan konversi seperti pada contoh di atas.

CATATAN: SAYA MENULIS KONDISI KESALAHAN HANYA UNTUK MEWUJUDKAN CUACA KONDISI INI DILAKSANAKAN ATAU BERLINGKAR-SINGKAT JIKA HASIL HASIL DALAM KESALAHAN BERARTI KONDISI YANG DILAKSANAKAN, KONDISI DILAKUKAN DENGAN SINGKAT, SINGKAT-SINGKAT.

PENJELASAN SEDERHANA

Mempertimbangkan,

WHERE 1 = 1 OR 2 = 2

karena kondisi pertama sedang dievaluasi menjadi BENAR , tidak ada artinya untuk mengevaluasi kondisi kedua karena evaluasi dalam nilai apa pun tidak akan mempengaruhi hasil sama sekali, sehingga peluang yang baik bagi Sql Server untuk menghemat waktu Eksekusi Kueri dengan melewatkan pemeriksaan atau evaluasi kondisi yang tidak perlu .

dalam hal "ATAU" jika kondisi pertama dievaluasi ke TRUE seluruh rantai yang dihubungkan oleh "ATAU" akan dianggap dievaluasi dengan benar tanpa mengevaluasi yang lain.

condition1 OR condition2 OR ..... OR conditionN

jika kondisi1 dievaluasi menjadi benar, istirahatkan semua kondisi sampai kondisiN akan dilewati. Dengan kata-kata umum pada penentuan TRUE pertama , semua kondisi lain yang dihubungkan oleh OR akan dilewati.

Pertimbangkan kondisi kedua

WHERE 1 = 0 AND 1 = 1

karena kondisi pertama sedang dievaluasi ke FALSE dievaluasi tidak ada artinya untuk mengevaluasi kondisi kedua karena evaluasi dalam nilai apa pun tidak akan mempengaruhi hasilnya sama sekali, jadi sekali lagi kesempatan yang baik untuk Sql Server untuk menghemat waktu Eksekusi Query dengan melewatkan pemeriksaan atau evaluasi kondisi yang tidak perlu .

dalam kasus "DAN" jika kondisi pertama dievaluasi menjadi SALAH seluruh rantai yang terhubung dengan "DAN" akan dianggap sebagai dievaluasi ke SALAH tanpa mengevaluasi yang lain.

condition1 AND condition2 AND ..... conditionN

jika condition1 dievaluasi menjadi FALSE , istirahatkan semua kondisi sampai conditionN akan dilewati. Dengan kata-kata umum pada penentuan FALSE pertama , semua kondisi lain yang ditautkan oleh AND akan dilewati.

OLEH KARENA ITU, PROGRAMER BIJAK HARUS SELALU MEMPROGRAM RANTAI KONDISI SEPERTI YANG, KURANGNYA MURNI ATAU KONDISI YANG PALING MENGHAPUS DITERAPKAN PERTAMA, ATAU MENGATUR KETENTUAN DALAM SEPERTI YANG BISA DIBUTUHKAN.

RkHirpara
sumber
Alasan downvote: selalu menguji hal-hal di server nyata dengan data realistis. Sepertinya komentar saya sebelumnya dimakan.
Jasmine