¿Por qué aparece un error de consulta con un conjunto de resultados vacío en SQL Server 2012?

31

Al ejecutar las siguientes consultas en MS SQL Server 2012, la segunda consulta falla pero no la primera. Además, cuando se ejecuta sin las cláusulas where, ambas consultas fallarán. No sé por qué fallaría, ya que ambos deberían tener conjuntos de resultados vacíos. Cualquier ayuda / visión es apreciada.

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1
DavidN
fuente

Respuestas:

39

Una mirada inicial a los planes de ejecución muestra que la expresión 1/0se define en los operadores de Calcular Escalar:

Planos graficos

Ahora, a pesar de que los planes de ejecución comienzan a ejecutarse en el extremo izquierdo, invocando iterativamente Openy GetRowmétodos en iteradores secundarios para devolver resultados, SQL Server 2005 y posterior contiene una optimización mediante la cual las expresiones a menudo solo son definidas por un Escalar de cómputo, con evaluación diferida hasta un posterior La operación requiere el resultado :

Es posible que los operadores escalares computacionales que aparecen en los Showplans generados por SET STATISTICS XML no contengan el elemento RunTimeInformation.  En los planes gráficos, las filas reales, los rebobinados reales y los rebobinados reales pueden estar ausentes de la ventana Propiedades cuando la opción Incluir plan de ejecución real está seleccionada en SQL Server Management Studio.  Cuando esto ocurre, significa que aunque estos operadores se utilizaron en el plan de consulta compilado, su trabajo fue realizado por otros operadores en el plan de consulta en tiempo de ejecución.  También tenga en cuenta que el número de ejecuciones en la salida de Showplan generada por SET STATISTICS PROFILE es equivalente a la suma de rebobinados y rebobinados en Showplans generados por SET STATISTICS XML.  De: Libros en línea de MSDN

En este caso, el resultado de la expresión solo es necesario cuando se ensambla la fila para regresar al cliente (lo que se puede pensar que ocurre en el SELECTícono verde ). Según esa lógica, la evaluación diferida significaría que la expresión nunca se evalúa porque ninguno de los planes genera una fila de retorno. Para trabajar un poco el punto, ni el Clustered Index Seek ni el Table Scan devuelven una fila, por lo que no hay una fila para ensamblar y devolver al cliente.

Sin embargo, hay una optimización separada por la cual algunas expresiones pueden identificarse como constantes de tiempo de ejecución y evaluarse una vez antes de que comience la ejecución de la consulta . En este caso, se puede encontrar una indicación de esto en el XML del plan de presentación (plan de búsqueda de índice agrupado a la izquierda, plan de escaneo de tabla a la derecha):

Showplan XML

Escribí más sobre los mecanismos subyacentes y cómo pueden afectar el rendimiento en esta publicación de blog . Usando la información proporcionada allí, podemos modificar la primera consulta para que ambas expresiones se evalúen y se almacenen en caché antes de que comience la ejecución:

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

Ahora, el primer plan también contiene una referencia de expresión constante, y ambas consultas producen el mensaje de error. El XML para la primera consulta contiene:

Expresión constante

Más información: Calcular escalares, expresiones y rendimiento

Paul White dice GoFundMonica
fuente
21

Voy a adivinar inteligentemente (y en el proceso probablemente atraiga a un gurú de SQL Server que pueda dar una respuesta realmente detallada).

La primera consulta aborda la ejecución como:

  1. Escanear el índice de la clave primaria
  2. Busque los valores en la tabla de datos necesarios para la consulta

Elige esta ruta porque tiene una wherecláusula en la clave primaria. Nunca llega al segundo paso, por lo que la consulta no falla.

El segundo no tiene una clave principal para ejecutarse, por lo que aborda la consulta como:

  1. Haga un escaneo completo de la tabla de los datos y recupere los valores necesarios

Uno de esos valores está 1/0causando el problema.

Este es un ejemplo de SQL Server que optimiza la consulta. En su mayor parte, esto es algo bueno. SQL Server moverá las condiciones de la selectoperación de escaneo a la tabla. Esto a menudo ahorra pasos en la evaluación de la consulta.

Pero, esta optimización no es algo bueno absoluto. De hecho, parece violar la documentación de SQL Server en sí misma que dice que la wherecláusula se evalúa antes que select. Bueno, podrían tener una explicación erudita de lo que esto significa. Sin embargo, para la mayoría de los humanos, procesar lógicamente el whereantes del selectsignificaría (entre otras cosas) "no generar selecterrores de cláusula en filas no devueltas al usuario".

Gordon Linoff
fuente
1
+1 no tengo idea si tienes razón, pero la mejor respuesta que puedo ver dada la única diferencia es la clave principal.
1
@GordonLinoff Paul Randal acaba de confirmar a través de Twitter que su respuesta fue contundente.
SchmitzIT
44
@Todavía, el orden real de ejecución, por diferente que sea, no debería generar mensajes de error como ese.
ypercubeᵀᴹ
77
@ypercube Erland Sommarskog estaría de acuerdo con usted (elemento de conexión)
Paul White dice GoFundMonica
2
Gracias por el puntero: inicié sesión y voté por la solicitud.
Gordon Linoff