Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Aliran Bersyarat SQL Server

Saya akan menulis ulang tes sebagai

IF CASE
     WHEN EXISTS (SELECT ...) THEN CASE
                                   WHEN EXISTS (SELECT ...) THEN 1
                                 END
   END = 1  

Ini menjamin korsleting seperti yang dijelaskan di sini, tetapi ini berarti Anda harus memilih yang termurah untuk dievaluasi terlebih dahulu daripada menyerahkannya kepada pengoptimal.

Dalam pengujian saya yang sangat terbatas di bawah ini, hal berikut tampaknya benar saat menguji

1. EXISTS AND EXISTS

EXISTS AND EXISTS versi tampaknya paling bermasalah. Rantai ini bersama-sama beberapa semi luar bergabung. Tidak ada kasus yang mengatur ulang urutan tes untuk mencoba dan melakukan yang lebih murah terlebih dahulu (masalah yang dibahas di paruh kedua posting blog ini). Dalam IF ... versi itu tidak akan ada bedanya jika itu karena tidak korsleting. Namun ketika predikat gabungan ini dimasukkan ke dalam WHERE klausa rencana berubah dan terjadi korsleting sehingga penataan ulang bisa bermanfaat.

/*All tests are testing "If False And False"*/

IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
PRINT 'Y'
/*
Table 'spt_values'. Scan count 1, logical reads 9
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
PRINT 'Y'
/*
Table 'spt_monitor'. Scan count 1, logical reads 1
Table 'spt_values'. Scan count 1, logical reads 9
*/

SELECT 1
WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

SELECT 1
WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_values'. Scan count 1, logical reads 9

*/

Rencana untuk semua ini tampak sangat mirip. Alasan perbedaan perilaku antara SELECT 1 WHERE ... versi dan IF ... versi adalah bahwa untuk yang pertama jika kondisinya salah maka perilaku yang benar adalah tidak mengembalikan hasil sehingga hanya menghubungkan OUTER SEMI JOINS dan jika salah satu salah maka baris nol diteruskan ke baris berikutnya.

Namun IF versi selalu perlu mengembalikan hasil 1 atau nol. Paket ini menggunakan kolom penyelidikan di sambungan luarnya dan menyetelnya ke false jika EXISTS tes tidak lulus (daripada hanya membuang baris). Ini berarti selalu ada 1 baris yang dimasukkan ke Gabung berikutnya dan selalu dieksekusi.

CASE versi memiliki rencana yang sangat mirip tetapi menggunakan PASSTHRU predikat yang digunakan untuk melewati eksekusi JOIN jika sebelumnya THEN kondisi tidak terpenuhi. Saya tidak yakin mengapa menggabungkan AND s tidak akan menggunakan pendekatan yang sama.

2. EXISTS OR EXISTS

EXISTS OR EXISTS versi menggunakan gabungan (UNION ALL ) operator sebagai input dalam ke semi join luar. Pengaturan ini berarti bahwa ia dapat berhenti meminta baris dari sisi dalam segera setelah yang pertama dikembalikan (yaitu dapat secara efektif membuat hubungan pendek) Semua 4 kueri berakhir dengan rencana yang sama di mana predikat yang lebih murah dievaluasi terlebih dahulu.

/*All tests are testing "If True Or True"*/

IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1)  
OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
PRINT 'Y'
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1) 
PRINT 'Y'
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

SELECT 1
WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1)  
OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

SELECT 1
WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1) 
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

3. Menambahkan ELSE

Terpikir oleh saya untuk mencoba hukum De Morgan untuk mengonversi AND ke OR dan lihat apakah itu membuat perbedaan. Mengonversi kueri pertama memberi

IF NOT ((NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)))
PRINT 'Y'
ELSE
PRINT 'N'
/*
Table 'spt_monitor'. Scan count 1, logical reads 1
Table 'spt_values'. Scan count 1, logical reads 9
*/

Jadi ini masih tidak ada bedanya dengan perilaku hubungan arus pendek. Namun jika Anda menghapus NOT dan membalik urutan IF ... ELSE kondisikan sekarang tidak korsleting!

IF (NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1))
PRINT 'N'
ELSE
PRINT 'Y'
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kunci Utama di SQL Server

  2. Cara Mendapatkan Semua Tabel yang Memiliki Batasan Kunci Utama Dibuat di Database SQL Server - Tutorial SQL Server / TSQL 57

  3. Algoritma pengurutan SQL Server GUID. Mengapa?

  4. Gunakan OBJECTPROPERTY() untuk Menentukan Apakah Objek adalah Tampilan di SQL Server

  5. Cara memfilter Baris dengan Nilai Null di Select Statement di SQL Server - Tutorial SQL Server / TSQL Bagian 110