visualizar query plan formas estimated ejecución ejecucion analyze sql sql-execution-plan

formas - sql select query plan



Rendimiento de las variantes de uso SQL "EXISTS" (9)

# 3 Debería ser el mejor, ya que no necesitas los datos devueltos de todos modos. Traer los campos solo agregará una sobrecarga adicional

¿Hay alguna diferencia en el rendimiento de las siguientes tres declaraciones SQL?

SELECT * FROM tableA WHERE EXISTS (SELECT * FROM tableB WHERE tableA.x = tableB.y) SELECT * FROM tableA WHERE EXISTS (SELECT y FROM tableB WHERE tableA.x = tableB.y) SELECT * FROM tableA WHERE EXISTS (SELECT 1 FROM tableB WHERE tableA.x = tableB.y)

Todos deberían trabajar y devolver el mismo conjunto de resultados. ¿Pero importa si el SELECT interno selecciona todos los campos de la tabla B, un campo o solo una constante?

¿Hay alguna mejor práctica cuando todas las declaraciones se comportan de la misma manera?


En SQL Server al menos,

La cantidad más pequeña de datos que se pueden leer desde el disco es una sola "página" de espacio en disco. Tan pronto como el procesador lea un registro que satisfaga los predicados de la subconsulta, puede detenerse. La subconsulta no se ejecuta como si estuviera parada por sí misma, y ​​luego se incluye en la consulta externa, se ejecuta como parte del plan de consulta completo para todo. Entonces cuando se usa como subconsulta, realmente no importa lo que está en la cláusula Select, nada se devuelve "a la consulta externa de todos modos, excepto un booleano para indicar si se encontró o no un registro único ...

Los tres usan exactamente el mismo plan de ejecución

Siempre uso [Seleccionar * de ...] porque creo que se lee mejor, al no dar a entender que deseo que algo en particular sea devuelto de la subconsulta.

EDITAR: Desde dave costa comment ... Oracle también usa el mismo plan de ejecución para las tres opciones


Esta es una de esas preguntas que raya en iniciar algún tipo de guerra santa.

Hay una buena discusión al respecto aquí .

Creo que la respuesta es probablemente utilizar la tercera opción, pero el aumento de la velocidad es infinitesimal, realmente no vale la pena preocuparse. Es fácilmente el tipo de consulta que SQL Server puede optimizar internamente de todos modos, por lo que puede encontrar que todas las opciones son equivalentes.


Plan de ejecución . Aprende, úsala, ámala

No hay forma posible de adivinar, realmente.


Definitivamente # 1. Se ve "aterrador", pero se da cuenta de que el optimizador hará lo correcto y es expresivo de la intención. También hay una pequeña bonificación de error tipográfico si uno accidentalmente piensa que EXISTE pero escribe IN. # 2 es aceptable pero no expresivo. La tercera opción apesta en mi opinión no tan humilde. Está demasiado cerca de decir "si" no existe ningún valor "para la comodidad.

En general, es importante no tener miedo de escribir código que parece ineficiente si proporciona otros beneficios y no afecta el rendimiento.

Es decir, el optimizador casi siempre ejecutará su complicada combinación / selección / agrupación de wizardry para guardar un EXISTS / subconsulta simple de la misma manera.

Después de haberte felicitado por haber reescrito hábilmente ese OR desagradable de una unión, eventualmente te darás cuenta de que el optimizador todavía usaba el mismo plan de ejecución para resolver la consulta mucho más fácil de entender con OR integrado o de todos modos.

La moraleja de la historia es conocer tu optimizador de plataformas. Pruebe cosas diferentes y vea lo que se está haciendo en realidad porque las suposiciones rampantes de las sacudidas de rodilla con respecto a la optimización de consultas "decorativas" casi siempre son incorrectas e irrelevantes según mi experiencia.


La verdad sobre la cláusula EXISTS es que la cláusula SELECT no se evalúa en una cláusula EXISTS; podrías intentar:

SELECT * FROM tableA WHERE EXISTS (SELECT 1/0 FROM tableB WHERE tableA.x = tableB.y)

... y debería esperar un error de división por cero, pero no lo hará porque no se evalúa. Es por eso que mi hábito es especificar NULL en un EXISTS para demostrar que se puede ignorar el SELECT:

SELECT * FROM tableA WHERE EXISTS (SELECT NULL FROM tableB WHERE tableA.x = tableB.y)

Todo lo que importa en una cláusula EXISTS es las cláusulas FROM y beyond: WHERE, GROUP BY, HAVING, etc.

Esta pregunta no se marcó con una base de datos en mente, y debería ser porque los proveedores manejan las cosas de manera diferente, así que pruebe y verifique los planes de explicación / ejecución para confirmar. Es posible que el comportamiento cambie entre versiones ...


Me doy cuenta de que esta es una publicación anterior, pero creo que es importante aclarar por qué uno puede elegir un formato sobre otro.

En primer lugar, como han señalado otros, se supone que el motor de la base de datos ignora la cláusula Select. Cada versión de SQL Server tiene / does, Oracle hace, MySQL lo hace y así sucesivamente. En muchas, muchas lunas de desarrollo de bases de datos, solo he encontrado un DBMS que no ignoró correctamente la cláusula Select: Microsoft Access. Específicamente, versiones anteriores de MS Access (no puedo hablar con las versiones actuales).

Antes de descubrir esta "característica", solía usar Exists( Select *... Sin embargo, descubrí que MS Access se transmitía en cada columna de la subconsulta y luego se descartaba ( Select 1/0 tampoco funcionaba) ). Eso me convenció de cambiar a Select 1 Si incluso un DBMS fuera estúpido, podría existir otro.

Exists( Select 1... escritura Exists( Select 1... es tan claramente claro en la intención de transmitir (es francamente tonto decir "Está demasiado cerca de decir" si "no hay valor" existe "para la comodidad") y hace las probabilidades de que un SGBD haga algo estúpido con la declaración Select casi imposible. Select Null tendría el mismo propósito, pero es simplemente más caracteres para escribir.

Cambié a Exists( Select 1 para estar absolutamente seguro de que el DBMS no podría ser estúpido. Sin embargo, eso fue hace muchas lunas, y hoy esperaría que la mayoría de los desarrolladores esperen ver Exists( Select * que funcionará exactamente igual).

Dicho esto, puedo proporcionar una buena razón para evitar Exists(Select * incluso si su DBMS lo evalúa correctamente. Es mucho más fácil encontrar y anular todos los usos de Select * si no tiene que omitir todas las instancias de su uso en una cláusula de Exists.


Además de lo que otros han dicho, la práctica de usar SELECT 1 originó en el antiguo Microsoft SQL Server (anterior a 2005): su optimizador de consultas no era lo suficientemente inteligente como para evitar obtener físicamente campos de la tabla para SELECT * . Ningún otro SGBD, que yo sepa, tiene esta deficiencia.

EXISTS prueba la existencia de filas, no lo que contienen, por lo que, aparte de alguna peculiaridad del optimizador similar a la anterior, en realidad no importa lo que esté en la lista SELECT.

El SELECT * parece ser el más habitual, pero otros también son aceptables.


EXISTS devuelve una información booleana no real, dicha práctica recomendada es usar # 3.