¿Se evalúa el cortocircuito de la cláusula WHERE de SQL?

142

¿Se evalúan las expresiones booleanas en las cláusulas SQL WHERE de cortocircuito ?

Por ejemplo:

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

Si @key IS NULL se evalúa como verdadero, ¿ @key IS NOT NULL AND @key = t.Key evaluado?

Si no, ¿por qué no?

En caso afirmativo, ¿está garantizado? ¿Forma parte de ANSI SQL o es específico de la base de datos?

Si la base de datos es específica, SqlServer? ¿Oráculo? MySQL?

Greg Dean
fuente
¿No es redundante la cláusula @key NO ES NULO? La cláusula @key IS NULL en el LHS se encarga de esto, ¿no?
gastador
10
@splender - depende de la respuesta a la pregunta
Greg Dean
@ Greg: Estoy de acuerdo con el gastador. No veo la falta o presencia de cortocircuito haciendo ninguna diferencia. Si @key IS NULL, entonces @key = t.Key siempre devolverá false, como NULL! = NULL (es por eso que usamos IS NULL, después de todo).
Michael Madsen
14
@Michael y @spender: el punto de la pregunta es si la segunda condición se evalúa o no. El punto de la pregunta no es si esta declaración SQL específica está escrita en la menor cantidad de caracteres posible. En ejemplos más complicados, sin duda importaría, como si la cláusula where cortocircuitara, podría escribir expresiones que de otro modo serían erróneas.
Greg Dean el
2
El cortocircuito implica evaluar las condiciones de izquierda a derecha. Dada una condición tal como WHERE a = 1 AND b = 2podría ser eficiente para el motor de base de datos encontrar todas las filas donde b = 2 primero, luego filtrar donde a = 1. Si solicita garantía, entonces el optimizador se vuelve inútil.
Salman A

Respuestas:

72

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

6.3.3.3 Orden de evaluación de la regla

[...]

Cuando la precedencia no está determinada por los formatos o por paréntesis, la evaluación efectiva de las expresiones generalmente se realiza de izquierda a derecha. Sin embargo, depende de la implementación si las expresiones se evalúan realmente de izquierda a derecha, particularmente cuando los operandos u operadores pueden provocar condiciones o si los resultados de las expresiones se pueden determinar sin evaluar completamente todas las partes de la expresión.

Comunidad
fuente
44
¿Depende de la implementación? Excelente. Es bueno saberlo también. Al menos CASEestá en cortocircuito.
dakab
3
¿No significa esto que las evaluaciones de expresión están mal definidas? "(0 = 0 OR NULL)", siempre es NULL si se evalúan todos los términos, pero siempre es cierto si se evalúa de izquierda a derecha y en cortocircuito.
user48956
66
SQL es un lenguaje declarativo, básicamente expresa la lógica del cálculo sin describir su flujo de control; lo que contradice el estilo imperativo de la evaluación de cortocircuito y sus consecuencias.
Jorge García
No lo había pensado de esa manera @JorgeGarcia. Supongo que la evaluación de cortocircuito fuerza implícitamente un orden en las operaciones. Estoy luchando con algún código en el que esto posiblemente sea la raíz de un problema sutil. Gracias por la perspicacia.
Carnot Antonio Romero
58

De lo anterior, el cortocircuito no está realmente disponible.

Si lo necesita, le sugiero una declaración de caso:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1siempre se evalúa, pero solo uno de Expr2y Expr3se evaluará por fila.

PMc
fuente
3
Eso depende de la implementación del RDBMS, supongo. Al menos para SQL Server, existe al menos una excepción que está documentada para no mostrar este comportamiento (es decir, cortocircuito); cf CASO (Transact-SQL): observaciones . Cité este caso en esta respuesta que di sobre la pregunta Sql: orden explícito de las condiciones WHERE .
TT.
1
Expresión de caso , no declaración.
jarlh
19

Creo que este es uno de los casos en que lo escribiría como si no tuviera un cortocircuito, por tres razones.

  1. Porque para MSSQL, no se resuelve mirando BOL en el lugar obvio, por lo que para mí eso lo hace canónicamente ambiguo.

  2. porque al menos sé que mi código funcionará. Y lo que es más importante, también lo harán los que vengan después de mí, así que no los estoy preparando para preocuparse por la misma pregunta una y otra vez.

  3. Escribo con suficiente frecuencia para varios productos DBMS, y no quiero tener que recordar las diferencias si puedo solucionarlos fácilmente.

dkretz
fuente
44
Gran sugerencia No responde la pregunta, pero es un gran punto de vista pragmático. entonces +1
Greg Dean
12

No creo que se garantice un cortocircuito en SQL Server (2005). SQL Server ejecuta su consulta a través de su algoritmo de optimización que tiene en cuenta muchas cosas (índices, estadísticas, tamaño de tabla, recursos, etc.) para llegar a un plan de ejecución efectivo. Después de esta evaluación, no puede estar seguro de que su lógica de cortocircuito esté garantizada.

Me encontré con la misma pregunta hace algún tiempo y mi investigación realmente no me dio una respuesta definitiva. Puede escribir una pequeña consulta para darle una prueba de que funciona, pero ¿puede estar seguro de que a medida que aumenta la carga en su base de datos, las tablas crecen y las cosas se optimizan y cambian en la base de datos? sostener. No pude y, por lo tanto, erré por precaución y utilicé la cláusula CASO en DONDE para garantizar un cortocircuito.

Mehmet Aras
fuente
7

Debe tener en cuenta cómo funcionan las bases de datos. Dada una consulta parametrizada, la base de datos crea un plan de ejecución basado en esa consulta sin los valores para los parámetros. Esta consulta se usa cada vez que se ejecuta, independientemente de los valores reales suministrados. Si los cortocircuitos de consulta con ciertos valores no serán importantes para el plan de ejecución.

Mente lógica
fuente
66
¡Importa para la velocidad de ejecución!
user4951
Solo porque así es como funciona actualmente no significa que no se pueda cambiar. Tenemos que separar el modelo / semántica de la implementación. Los planes de ejecución se implementan internamente para optimizar la ejecución de consultas ... y la semántica de cortocircuito no solo contradice la naturaleza declarativa de SQL, sino que también puede limitar tales optimizaciones. Sin embargo, si el DBMS apoyara la semántica de evaluación de cortocircuito, la implementación de los planes de ejecución cambiaría para admitir dicha semántica.
Jorge García
3

Normalmente uso esto para parámetros opcionales. ¿Es esto lo mismo que cortocircuito?

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

Esto me da la opción de pasar -1 o lo que sea para tener en cuenta la verificación opcional de un atributo. A veces esto implica unirse en varias tablas, o preferiblemente una vista.

Muy útil, no del todo seguro del trabajo extra que le da al motor db.

p.campbell
fuente
2

Para SQL Server, creo que depende de la versión, pero mi experiencia con SQL Server 2000 es que todavía evalúa @key = t.Key incluso cuando @key es nulo. En otras palabras, no hace un cortocircuito eficiente al evaluar la cláusula WHERE.

He visto personas que recomiendan una estructura como su ejemplo como una forma de hacer una consulta flexible donde el usuario puede ingresar o no ingresar varios criterios. Mi observación es que Key todavía está involucrado en el plan de consulta cuando @key es nulo y si Key está indexado, entonces no usa el índice de manera eficiente.

Este tipo de consulta flexible con criterios variables es probablemente un caso en el que SQL creado dinámicamente es realmente la mejor manera de hacerlo. Si @key es nulo, simplemente no lo incluya en la consulta.

tetranz
fuente
2

Acabo de tropezar con esta pregunta, y ya había encontrado esta entrada de blog: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

El servidor SQL es libre de optimizar una consulta en cualquier lugar que le parezca conveniente, por lo que en el ejemplo dado en la publicación del blog, no puede confiar en los cortocircuitos.

Sin embargo, un CASO aparentemente está documentado para evaluarlo en el orden escrito: revise los comentarios de esa publicación de blog.

Stolsvik
fuente
1

La característica principal de la evaluación de cortocircuito es que deja de evaluar la expresión tan pronto como se puede determinar el resultado. Eso significa que el resto de la expresión puede ignorarse porque el resultado será el mismo independientemente de si se evalúa o no.

Los operadores booleanos binarios son conmutativos, lo que significa:

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

Por lo tanto, no hay garantía en el orden de evaluación. El orden de evaluación será determinado por el optimizador de consultas.

En lenguajes con objetos puede haber situaciones en las que puede escribir expresiones booleanas que solo pueden evaluarse con la evaluación de cortocircuito. La construcción de su código de muestra a menudo se usa en dichos lenguajes (C #, Delphi, VB). Por ejemplo:

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

Este ejemplo de C # causará una excepción si someString == nullse evaluará completamente. En la evaluación de cortocircuito, funcionará siempre.

SQL opera solo en variables escalares (sin objetos) que no se pueden inicializar, por lo que no hay forma de escribir expresiones booleanas que no se puedan evaluar. Si tiene algún valor NULL, cualquier comparación devolverá falso.

Eso significa que en SQL no puede escribir expresiones que se evalúen de manera diferente dependiendo del uso de cortocircuito o evaluación completa.

Si la implementación de SQL utiliza la evaluación de cortocircuito, solo puede acelerar la ejecución de consultas.

Zendar
fuente
1
Sí, los operadores booleanos son conmutativos. No creo que los objetos (o no) tengan nada que ver con eso.
Greg Dean
1

No sé sobre el cortocircuito, pero lo escribiría como una declaración if-else

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

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

end

Además, las variables siempre deben estar en el lado derecho de la ecuación. Esto lo hace sargable.

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

DForck42
fuente
1
¿Alguien puede corroborarlo sobre las variables de la derecha? Por alguna razón me cuesta creerlo.
Greg Dean
searchoracle.techtarget.com/expert/KnowledgebaseAnswer/… no puedo encontrar mucho más en este momento
DForck42
Según tengo entendido el artículo. Está hablando de que las funciones en los nombres de columna no son modificables. Lo cual entiendo. Sin embargo, no creo que (A = @a) o (@a = A) importen.
Greg Dean
podría estar equivocado. podría ser una buena pregunta si aún no existe.
DForck42
1

Debajo de una prueba rápida y sucia en SQL Server 2008 R2:

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

Esto vuelve inmediatamente sin registros. El tipo de comportamiento de cortocircuito estaba presente.

Entonces probé esto:

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

sabiendo que ningún registro satisfaría esta condición:

(a field from table) < 0

Esto tomó varios segundos, lo que indica que el comportamiento del cortocircuito ya no existía y que la operación compleja se estaba evaluando para cada registro.

Espero que esto ayude a los chicos.

Jorge
fuente
1
Supongo que la primera consulta se "cortocircuitó" en tiempo de compilación, antes de que la ejecución del plan realmente comenzara.
Louis Somers
1

Aquí hay una demostración para demostrar que MySQL realiza un cortocircuito en la cláusula WHERE :

http://rextester.com/GVE4880

Esto ejecuta las siguientes consultas:

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;

La única diferencia entre estos es el orden de los operandos en la condición OR.

myslowfunctionduerme deliberadamente por un segundo y tiene el efecto secundario de agregar una entrada a una tabla de registro cada vez que se ejecuta. Estos son los resultados de lo que se registra al ejecutar las dos consultas anteriores:

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

Lo anterior muestra que una función lenta se ejecuta más veces cuando aparece en el lado izquierdo de una condición OR cuando el otro operando no siempre es verdadero (debido a un cortocircuito).

Steve Chambers
fuente
44
Hmm, lo que probablemente quisiste decir "Aquí hay una demostración para demostrar que MySQL realiza un cortocircuito en la cláusula WHERE en este caso particular :"
TT.
1
Claro, es solo una prueba de que puede suceder.
Steve Chambers
0

Esto toma 4 segundos adicionales en el analizador de consultas, por lo que puedo ver si IF ni siquiera está en corto ...

SET @ADate = NULL

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

¡Sería bueno tener una forma garantizada!

azulado
fuente
-2

Es obvio que el servidor MS Sql admite la teoría de cortocircuito para mejorar el rendimiento al evitar verificaciones innecesarias,

Ejemplo de apoyo:

SELECT 'TEST'
WHERE 1 = 'A'

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

Aquí, el primer ejemplo daría como resultado el error 'Error de conversión al convertir el valor varchar' A 'al tipo de datos int'.

Mientras que el segundo se ejecuta fácilmente ya que la condición 1 = 1 se evaluó como VERDADERA y, por lo tanto, la segunda condición no se ejecutó en absoluto.

Además

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

aquí la primera condición se evaluaría como falsa y, por lo tanto, el DBMS pasaría a la segunda condición y nuevamente obtendrá el error de conversión como en el ejemplo anterior.

NOTA: ESCRIBÍ LA CONDICIÓN ERRÓNEA SOLO PARA REALIZAR EL CLIMA LA CONDICIÓN SE EJECUTA O SE CORTA CORTOCIRCUITO SI LA CONSULTA RESULTA POR ERROR SIGNIFICA QUE LA CONDICIÓN SE EJECUTÓ, CORTOCIRCUITO DE OTRA MANERA.

EXPLICACIÓN SIMPLE

Considerar,

WHERE 1 = 1 OR 2 = 2

ya que la primera condición se evalúa como VERDADERA , no tiene sentido evaluar la segunda condición porque su evaluación en cualquier valor no afectaría el resultado en absoluto, por lo que es una buena oportunidad para que SQL Server ahorre tiempo de ejecución de consultas omitiendo la comprobación o evaluación de condiciones innecesarias .

en el caso de "OR" si la primera condición se evalúa como VERDADERA, toda la cadena conectada por "OR" se consideraría evaluada como verdadera sin evaluar otras.

condition1 OR condition2 OR ..... OR conditionN

Si la condición1 se evalúa como verdadera, descanse todas las condiciones hasta que se salte la condiciónN. En palabras generalizadas en la determinación del primer VERDADERO , se omitirán todas las demás condiciones vinculadas por OR.

Considera la segunda condición

WHERE 1 = 0 AND 1 = 1

ya que la primera condición se evalúa como FALSA evalúa como tiene sentido evaluar la segunda condición porque su evaluación en cualquier valor no afectaría el resultado en absoluto, por lo que nuevamente es una buena oportunidad para que Sql Server ahorre tiempo de ejecución de consultas omitiendo la comprobación o evaluación de condiciones innecesarias .

en caso de "Y" si la primera condición se evalúa como FALSA, toda la cadena conectada con el "Y" se consideraría evaluada como FALSA sin evaluar otras.

condition1 AND condition2 AND ..... conditionN

si la condición1 se evalúa como FALSA , descanse todas las condiciones hasta que se salte la condiciónN . En palabras generalizadas en la determinación del primer FALSO , se omitirán todas las demás condiciones vinculadas por AND .

POR LO TANTO, UN PROGRAMADOR SABIO DEBE SIEMPRE PROGRAMAR LA CADENA DE CONDICIONES DE TAL MANERA QUE, CONDICION MENOS GASTA O MÁS ELIMINADORA SE EVALUE PRIMERO, O ARREGLAR LA CONDICIÓN DE TAL MANERA QUE PUEDA TENER UN MÁXIMO BENEFICIO DE CORTO CIRCUITO

RkHirpara
fuente
Razón negativa: siempre pruebe cosas en un servidor real con datos realistas. Parece que mi comentario anterior fue comido.
Jasmine