2012-08-31 18 views
7

TIs ISNULL() ¿una función floja?¿La función ISNULL() del servidor Sql está floja/en cortocircuito?

Es decir, si I Código algo como lo siguiente:

SELECT ISNULL(MYFIELD, getMyFunction()) FROM MYTABLE

será siempre evaluar getMyFunction() o va a evaluarlo solamente en el caso en MYFIELD en realidad es nula?

+0

Puede agregar una declaración 'PRINT' a su función y descubrirlo usted mismo. –

+0

@JarrettMeyer Utilicé esa técnica para aprender a programar en mi niñez, pero no se aplica hoy en día porque no se sabe qué es el detalle de la implementación y cuál es el comportamiento documentado. Aprender es cada vez más difícil :(solo digo ... –

+2

@JarrettMeyer, 'PRINT' no es aceptable en un udf. – Kash

Respuesta

2

Es lo que crea que funcionará mejor.

Ahora es funcionalmente flojo, que es lo más importante. P.ej. Si col1 es una varchar que siempre contiene un número cuando col2 es nulo,

isnull(col2, cast(col1 as int)) 

funcionará.

Sin embargo, no se especifica si probará el molde antes o simultáneamente con la verificación nula y come el error si col2 no es nulo, o si solo probará el molde si col2 es nulo.

Por lo menos, esperaríamos que obtenga col1 en cualquier caso porque un solo escaneo de una tabla que obtenga 2 valores va a ser más rápido que dos escaneos obteniendo uno cada uno.

Los mismos comandos SQL se pueden ejecutar de formas muy diferentes, ya que las instrucciones que damos se convierten en operaciones de nivel inferior en función del conocimiento de los índices y las estadísticas sobre las tablas.

Por esa razón, en términos de rendimiento, la respuesta es "cuando parece que sería una buena idea, de lo contrario no lo es".

En términos de comportamiento observado, es flojo.

Editar: La respuesta de Mikael Eriksson muestra que hay casos que de hecho pueden ser un error debido a no ser perezoso. Mantendré mi respuesta aquí en términos del impacto en el rendimiento, pero la suya es vital en términos del impacto correcto en al menos algunos casos.

+0

Da una buena explicación del hecho de que puede o no ser flojo. en las decisiones de optimización del servidor. Gracias. – eidylon

+0

Bienvenido. Aunque añadiré una advertencia. –

3

A juzgar por el diferente comportamiento de

SELECT ISNULL(1, 1/0) 

SELECT ISNULL(NULL, 1/0) 

la primera SELECT devuelve 1, el segundo plantea un error Msg 8134, Level 16, State 1, Line 4 Divide by zero error encountered..

+0

Esto no es del todo confiable. Las subconsultas pueden causar problemas debido a las diferentes reglas de reescritura que entran en juego. – usr

+0

@usr, they no causará que la condición de error suceda si el primer campo es siempre nulo. Eso no quiere decir que el servidor no está calculando 1/0 y luego cometer el error cuando ve que la expresión no se usa, es libre de hacer lo que quiera con el mismo comportamiento externo. –

+0

@JonHanna, sí mi comentario fue dirigido a posibles problemas de rendimiento. – usr

2

Esta característica "perezosa" a la que se refiere de hecho se llama "cortocircuito"
Y NO siempre funciona especialmente si tiene un udf en la expresión ISNULL.
Comprobar este artículo, donde se llevaron a cabo pruebas para demostrarlo:
Short-circuiting (mainly in VB.Net and SQL Server)

T-SQL es un lenguaje declarativo, por tanto, no puede controlar el algoritmo utilizado para obtener los resultados .. simplemente declara lo que da como resultado que necesita. Es hasta el motor/optimizador de consultas para descubrir el plan rentable. Y en SQL Server, el optimizador usa la "detección de contradicciones", que nunca garantizará una evaluación de izquierda a derecha como lo haría en los lenguajes de procedimiento.


Para su ejemplo, hicieron una prueba rápida:
Creado el UDF escalar de valor para invocar la división por cero error:

CREATE FUNCTION getMyFunction 
(@MyValue INT) 
RETURNS INT 
AS 
BEGIN 
    RETURN (1/0) 
END 
GO 

Ejecutar la consulta siguiente no me dio un error de Divide by zero error encountered .

DECLARE @test INT 
SET @test = 1 
SET @test = ISNULL(@test, (dbo.getMyFunction(1))) 
SELECT @test 

Cambio de la SET el cuadro de abajo me dio el error Divide by zero error encountered.. (Introducido un SELECT en ISNULL)

SET @test = ISNULL(@test, (SELECT dbo.getMyFunction(1))) 

embargo, con valores en lugar de las variables, nunca me dio el error.

SELECT ISNULL(1, (dbo.getMyFunction(1))) 
SELECT ISNULL(1, (SELECT dbo.getMyFunction(1))) 

Así que a menos que realmente averiguar cómo el optimizador está evaluando estas expresiones para todas las permutaciones, que sería seguro para no depender de las capacidades de cortocircuito de T-SQL.

4

Esto funciona bien

declare @X int 
set @X = 1 
select isnull(@X, 1/0) 

Pero la introducción de un agregado será hacer que falle y demostrando que el segundo argumento podría ser evaluado antes de la primera, a veces.

declare @X int 
set @X = 1 
select isnull(@X, min(1/0)) 
+0

Buen lugar en los agregados. –

Cuestiones relacionadas