La clausola SQL WHERE è in corto circuito valutata?


142

Le espressioni booleane nelle clausole WHERE di SQL in cortocircuito vengono valutate ?

Per esempio:

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

Se @key IS NULL restituisce true, @key IS NOT NULL AND @key = t.Key viene valutato?

Se no, perché no?

Se sì, è garantito? Fa parte di ANSI SQL o è specifico del database?

Se specifico del database, SqlServer? Oracolo? MySQL?


La clausola @key IS NOT NULL non è ridondante? La clausola @key IS NULL sull'LHS si occupa di questo no?
spender

10
@splender - dipende dalla risposta alla domanda
Greg Dean,

@Greg: sono d'accordo con spender. Non vedo la mancanza o la presenza di cortocircuiti che fanno la differenza. Se @key IS NULL, allora @key = t.Key restituirà sempre false, come NULL! = NULL (ecco perché usiamo IS NULL, dopo tutto).
Michael Madsen,

14
@Michael and @spender - Il punto della domanda è: la seconda condizione valuta o no. Il punto della domanda non è: questa specifica istruzione SQL è scritta nel minor numero di caratteri possibile. In esempi più complicati sarebbe indubbiamente importante, come se la clausola where fosse in cortocircuito, si potrebbero scrivere espressioni che altrimenti sarebbero errate.
Greg Dean,

2
Il corto circuito implica la valutazione delle condizioni da sinistra a destra. Data una condizione come WHERE a = 1 AND b = 2potrebbe essere efficiente per il motore di database trovare tutte le righe dove prima b = 2, quindi filtrare dove a = 1. Se si richiede la garanzia, l'ottimizzatore diventa inutile.
Salman,

Risposte:


72

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

6.3.3.3 Ordine di valutazione delle regole

[...]

Laddove la precedenza non è determinata dai formati o dalle parentesi, la valutazione efficace delle espressioni viene generalmente eseguita da sinistra a destra. Tuttavia, dipende dall'implementazione se le espressioni vengono effettivamente valutate da sinistra a destra, in particolare quando operandi o operatori possono causare la generazione di condizioni o se i risultati delle espressioni possono essere determinati senza valutare completamente tutte le parti dell'espressione.


4
Attuazione-dipendente? Grande. Buono anche a sapersi. Almeno CASEè in corto circuito.
dakab,

3
Questo non significa che le valutazioni delle espressioni sono mal definite? "(0 = 0 OR NULL)", è sempre NULL se tutti i termini sono valutati, ma è sempre vero se valutato da sinistra a destra e in cortocircuito.
user48956

7
SQL è un linguaggio dichiarativo, fondamentalmente esprime la logica del calcolo senza descriverne il flusso di controllo; che in qualche modo contraddice lo stile imperativo della valutazione del corto circuito e le sue conseguenze.
Jorge Garcia,

Non ci avevo pensato in questo modo @JorgeGarcia. Immagino che la valutazione del corto circuito imponga implicitamente un ordine sulle operazioni. Sto lottando con un po 'di codice in cui questo è probabilmente alla radice di un problema sottile. Grazie per la comprensione.
Carnot Antonio Romero,

58

Da quanto sopra, il corto circuito non è realmente disponibile.

Se ne hai bisogno, ti suggerisco una dichiarazione Case:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1viene sempre valutato, ma solo uno di Expr2e Expr3verrà valutato per riga.


3
Dipende dall'implementazione del RDBMS presumo. Almeno per SQL Server, esiste almeno un'eccezione che è documentata per non mostrare questo comportamento (es. Cortocircuito); cf CASE (Transact-SQL) - Note . Ho citato questo caso in questa risposta che ho dato alla domanda Sql - Ordine esplicito delle condizioni DOVE? .
TT.

1
Espressione del caso , non dichiarazione.
Jarlh,

19

Penso che questo sia uno dei casi in cui lo scriverei come se non fosse in corto circuito, per tre motivi.

  1. Perché per MSSQL, non si risolve guardando BOL nel posto ovvio, quindi per me questo lo rende canonicamente ambiguo.

  2. perché almeno allora so che il mio codice funzionerà. E, cosa più importante, lo faranno anche quelli che vengono dopo di me, quindi non li sto preparando a preoccuparmi ripetutamente della stessa domanda.

  3. Scrivo abbastanza spesso per diversi prodotti DBMS e non voglio ricordare le differenze se posso aggirarli facilmente.


4
Ottimo consiglio Non risponde alla domanda, ma è un grande punto di vista pragmatico. quindi +1
Greg Dean,

12

Non credo che il corto circuito in SQL Server (2005) sia garantito. SQL Server esegue la query tramite il suo algoritmo di ottimizzazione che tiene conto di molte cose (indici, statistiche, dimensioni della tabella, risorse, ecc.) Per elaborare un piano di esecuzione efficace. Dopo questa valutazione, non puoi dire con certezza che la tua logica di corto circuito è garantita.

Qualche tempo fa ho incontrato la stessa domanda e la mia ricerca non mi ha dato una risposta definitiva. Puoi scrivere una piccola query per darti la prova che funziona, ma puoi essere sicuro che all'aumentare del carico sul tuo database, le tabelle diventano più grandi e le cose vengono ottimizzate e modificate nel database, tale conclusione sarà tenere. Non ho potuto e quindi sbagliato dal lato della cautela e ho usato CASE nella clausola WHERE per garantire il corto circuito.


7

Devi tenere presente come funzionano i database. Data una query con parametri, il database crea un piano di esecuzione basato su quella query senza i valori per i parametri. Questa query viene utilizzata ogni volta che viene eseguita la query indipendentemente da quali siano i valori effettivamente forniti. Se la query cortocircuita con determinati valori non importerà al piano di esecuzione.


6
è importante per la velocità di esecuzione!
user4951

Solo perché è così che funziona attualmente non significa che non possa essere modificato. Dobbiamo separare il modello / semantica dall'implementazione. I piani di esecuzione sono implementati internamente per ottimizzare l'esecuzione di query ... e la semantica di corto circuito non solo contraddice la natura dichiarativa di SQL ma può limitare tali ottimizzazioni. Tuttavia, se il DBMS dovesse supportare la semantica di valutazione del corto circuito, l'implementazione dei piani di esecuzione cambierebbe per supportare tale semantica.
Jorge Garcia,

3

Di solito lo uso per parametri opzionali. È lo stesso del corto circuito?

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

Questo mi dà la possibilità di passare -1 o qualunque altra cosa per tenere conto del controllo facoltativo di un attributo. A volte ciò comporta l'unione su più tabelle, o preferibilmente una vista.

Molto utile, non del tutto sicuro del lavoro extra che dà al motore db.


2

Per SQL Server, penso che dipenda dalla versione, ma la mia esperienza con SQL Server 2000 è che valuta ancora @key = t.Key anche quando @key è null. In altre parole, non esegue un corto circuito efficiente quando si valuta la clausola WHERE.

Ho visto le persone raccomandare una struttura come il tuo esempio come un modo per fare una query flessibile in cui l'utente può inserire o non inserire vari criteri. La mia osservazione è che Key è ancora coinvolto nel piano di query quando @key è null e se Key è indicizzato, non utilizza l'indice in modo efficiente.

Questo tipo di query flessibile con vari criteri è probabilmente un caso in cui SQL creato dinamicamente è davvero il modo migliore di procedere. Se @key è null, semplicemente non lo includi affatto nella query.


2

Mi sono appena imbattuto in questa domanda e avevo già trovato questo post di blog: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

Il server SQL è libero di ottimizzare una query ovunque ritenga opportuno, quindi nell'esempio riportato nel post del blog non puoi fare affidamento sul corto circuito.

Tuttavia, un CASE è apparentemente documentato per essere valutato nell'ordine scritto - controlla i commenti di quel post sul blog.


1

La principale caratteristica della valutazione del corto circuito è che smette di valutare l'espressione non appena il risultato può essere determinato. Ciò significa che il resto dell'espressione può essere ignorato perché il risultato sarà lo stesso indipendentemente dal fatto che sia valutato o meno.

Gli operatori booleani binari sono comutativi, ovvero:

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

quindi non esiste alcuna garanzia sull'ordine di valutazione. L'ordine di valutazione sarà determinato da Query Optimizer.

Nelle lingue con oggetti possono esserci situazioni in cui è possibile scrivere espressioni booleane che possono essere valutate solo con la valutazione del corto circuito. La costruzione del codice di esempio viene spesso utilizzata in tali lingue (C #, Delphi, VB). Per esempio:

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

Questo esempio C # causerà un'eccezione se someString == nullsarà valutato completamente. Nella valutazione del corto circuito, funzionerà ogni volta.

SQL funziona solo su variabili scalari (nessun oggetto) che non possono essere non inizializzate, quindi non c'è modo di scrivere espressioni booleane che non possano essere valutate. Se si dispone di un valore NULL, qualsiasi confronto restituirà false.

Ciò significa che in SQL non è possibile scrivere espressioni valutate in modo diverso a seconda dell'utilizzo del corto circuito o della valutazione completa.

Se l'implementazione SQL utilizza la valutazione del cortocircuito, può solo accelerare l'esecuzione della query.


1
Sì, gli operatori booleani sono commutativi. Non credo che gli oggetti (o no) abbiano qualcosa a che fare con esso.
Greg Dean,

1

non so di corto circuito, ma lo scriverei come un'istruzione if-else

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

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

end

inoltre, le variabili dovrebbero essere sempre sul lato destro dell'equazione. questo lo rende sargable.

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


1
Qualcuno può confermarlo sulle variabili a destra? Per qualche motivo ho difficoltà a crederci.
Greg Dean,

searchoracle.techtarget.com/expert/KnowledgebaseAnswer/… non riesco a trovare molto altro in questo momento
DForck42

Come capisco l'articolo. Si tratta di funzioni sui nomi delle colonne che non sono disponibili. Che ho capito. Tuttavia, non penso che (A = @a) o (@a = A) siano importanti.
Greg Dean,

potrei sbagliarmi. potrebbe essere una buona domanda se non esiste già.
DForck42,

1

Di seguito un test rapido e sporco su SQL Server 2008 R2:

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

Questo ritorna immediatamente senza record. Era presente un tipo di comportamento in corto circuito.

Quindi ho provato questo:

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

sapendo che nessun record soddisferebbe questa condizione:

(a field from table) < 0

Ciò ha richiesto diversi secondi, indicando che il comportamento del corto circuito non era più presente e l'operazione complessa veniva valutata per ogni record.

Spero che questo aiuti i ragazzi.


1
La mia ipotesi è che la prima query sia stata "cortocircuitata" in fase di compilazione, prima che l'esecuzione del piano effettivamente iniziata.
Louis Somers,

1

Ecco una demo per dimostrare che MySQL esegue il corto circuito della clausola WHERE :

http://rextester.com/GVE4880

Ciò esegue le seguenti query:

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;

L'unica differenza tra questi è l'ordine degli operandi nella condizione OR.

myslowfunctiondorme deliberatamente per un secondo e ha l'effetto collaterale di aggiungere una voce a una tabella di registro ogni volta che viene eseguita. Ecco i risultati di ciò che viene registrato durante l'esecuzione delle due query precedenti:

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

Quanto sopra mostra che una funzione lenta viene eseguita più volte quando appare sul lato sinistro di una condizione OR quando l'altro operando non è sempre vero (a causa di cortocircuiti).


4
Hmm, quello che probabilmente intendevi dire "Ecco una demo per dimostrare che MySQL esegue il cortocircuito della clausola WHERE in questo particolare caso :"
TT.

1
Certo, è solo una prova che può succedere.
Steve Chambers,

0

Questo richiede ulteriori 4 secondi nell'analizzatore di query, quindi da quello che posso vedere se non viene nemmeno messo in corto ...

SET @ADate = NULL

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

Sarebbe bello avere un modo garantito!


-2

È ovvio che il server MS Sql supporta la teoria dei cortocircuiti, per migliorare le prestazioni evitando controlli inutili,

Esempio di supporto:

SELECT 'TEST'
WHERE 1 = 'A'

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

Qui, il primo esempio provocherebbe l'errore "Conversione non riuscita durante la conversione del valore varchar" A "nel tipo di dati int."

Mentre la seconda viene eseguita facilmente poiché la condizione 1 = 1 viene valutata come VERA e quindi la seconda condizione non viene eseguita affatto.

Inoltre

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

qui la prima condizione verrebbe valutata come falsa e quindi il DBMS andrebbe per la seconda condizione e di nuovo si otterrà l'errore di conversione come nell'esempio sopra.

NOTA: HO UTILIZZATO LA CONDIZIONE ERRONE SOLO PER REALIZZARE IL METEO LA CONDIZIONE È ESEGUITA O CORTA CIRCUITO SE I RISULTATI DI QUERY IN ERRORE SIGNIFICANO LA CONDIZIONE ESEGUITA, CORTA CIRCUITAMENTE.

SPIEGAZIONE SEMPLICE

Tener conto di,

WHERE 1 = 1 OR 2 = 2

poiché la prima condizione viene valutata su TRUE , non ha senso valutare la seconda condizione perché la sua valutazione in qualsiasi valore non influirebbe affatto sul risultato, quindi è una buona opportunità per Sql Server salvare i tempi di esecuzione delle query saltando il controllo o la valutazione non necessari delle condizioni .

nel caso di "OR" se la prima condizione viene valutata su TRUE l'intera catena collegata da "OR" verrebbe considerata come valutata su true senza valutare altre.

condition1 OR condition2 OR ..... OR conditionN

se la condizione1 viene valutata come vera, riposa tutte le condizioni fino a quando la condizioneN verrebbe ignorata. In parole generalizzate alla determinazione del primo VERO , tutte le altre condizioni collegate da OR verrebbero ignorate.

Considera la seconda condizione

WHERE 1 = 0 AND 1 = 1

poiché la prima condizione viene valutata a FALSO non ha senso valutare la seconda condizione perché la sua valutazione in qualunque valore non influirebbe affatto sul risultato, quindi ancora una volta è una buona opportunità per Sql Server salvare i tempi di esecuzione delle query saltando il controllo o la valutazione non necessari delle condizioni .

nel caso di "AND" se la prima condizione viene valutata su FALSE l'intera catena connessa con "AND" verrebbe considerata come valutata su FALSE senza valutare altre.

condition1 AND condition2 AND ..... conditionN

se la condizione1 viene valutata su FALSO , riposa tutte le condizioni fino a quando la condizione N verrebbe ignorata. In parole generalizzate alla determinazione del primo FALSO , tutte le altre condizioni collegate da AND verrebbero ignorate.

Pertanto, un saggio programmatore dovrebbe sempre programmare la catena di condizioni in tal modo che, meno costosa o la maggior parte delle condizioni ELIMINANTI OTTIENE VALUTATE PER PRIMA, O DISPONIBILI LE CONDIZIONI IN QUANTO POSSIBILE ASSUMERE IL MASSIMO VANTAGGIO DEL CORTO CIRCUITO


Motivo del downvote: testare sempre le cose su un server reale con dati realistici. Sembra che il mio commento precedente sia stato mangiato.
Jasmine,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.