sql >> Database teknologi >  >> RDS >> Sqlserver

SQL Server betinget flow

Jeg ville omskrive testen som

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

Dette garanterer kortslutning som beskrevet her, men det betyder, at du skal vælge den billigste for at evaluere på forhånd i stedet for at overlade det til optimizeren.

I mine ekstremt begrænsede test nedenfor syntes følgende at holde stik, når jeg testede

1. EXISTS AND EXISTS

EXISTS AND EXISTS version virker mest problematisk. Dette kæder nogle ydre semi-sammenføjninger sammen. I ingen af ​​tilfældene omarrangerede den rækkefølgen af ​​testene for at prøve at lave den billigere først (et problem diskuteret i anden halvdel af dette blogindlæg). I IF ... version, ville det ikke have gjort nogen forskel, hvis det havde gjort det, da det ikke kortsluttede. Men når dette kombinerede prædikat er sat i en WHERE klausul planen ændres, og det gør det kortslutning, så omarrangering kunne have været gavnlig.

/*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 */

Planerne for alle disse ser meget ens ud. Årsagen til forskellen i adfærd mellem SELECT 1 WHERE ... version og IF ... version er, at for den tidligere, hvis betingelsen er falsk, så er den korrekte adfærd at returnere intet resultat, så det kæder bare OUTER SEMI JOINS og hvis en er falsk, så går nul rækker videre til den næste.

Men IF version altid skal returnere et resultat på 1 eller nul. Denne plan bruger en probesøjle i dens ydre joinforbindelser og indstiller denne til falsk, hvis EXISTS prøven er ikke bestået (i stedet for blot at kassere rækken). Det betyder, at der altid er 1 række, der føres ind i den næste Join, og den bliver altid udført.

CASE version har en meget lignende plan, men den bruger en PASSTHRU prædikat, som den bruger til at springe udførelse af JOIN over, hvis den forrige THEN betingelsen ikke var opfyldt. Jeg er ikke sikker på, hvorfor kombineret AND s ville ikke bruge den samme tilgang.

2. EXISTS OR EXISTS

EXISTS OR EXISTS version brugte en sammenkædning (UNION ALL ) operatør som det indre input til en ydre semi join. Dette arrangement betyder, at den kan stoppe med at anmode om rækker fra indersiden, så snart den første er returneret (dvs. den kan effektivt kortslutte). Alle 4 forespørgsler endte med den samme plan, hvor det billigere prædikat blev evalueret først.

/*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. Tilføjelse af en ELSE

Det faldt mig ind at prøve De Morgans lov om at konvertere AND til OR og se om det gjorde nogen forskel. Konvertering af den første forespørgsel giver

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
*/
 

Så dette gør stadig ingen forskel for kortslutningsadfærden. Men hvis du fjerner NOT og omvendt rækkefølgen af ​​IF ... ELSE forhold, det nu gør kortslutning!

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. ORA-00936:manglende udtryksorakel

  2. Sådan fungerer LOG2() i MariaDB

  3. Databasemodel for en køreskoles reservationssystem. Del 1

  4. 5 Fordele ved proaktiv overvågning af databaseydelse