En esta excelente pregunta SO , se discutieron las diferencias entre CTE
y sub-queries
.
Me gustaría preguntar específicamente:
¿En qué circunstancia cada uno de los siguientes es más eficiente / más rápido?
- CTE
- Subconsulta
- Tabla temporal
- Variable de tabla
Tradicionalmente, he usado mucho temp tables
en el desarrollo stored procedures
, ya que parecen más legibles que muchas subconsultas entrelazadas.
Non-recursive CTE
s encapsulan conjuntos de datos muy bien y son muy legibles, pero ¿hay circunstancias específicas en las que se pueda decir que siempre funcionarán mejor? ¿O se trata de tener que jugar con las diferentes opciones para encontrar la solución más eficiente?
EDITAR
Recientemente me han dicho que, en términos de eficiencia, las tablas temporales son una buena primera opción, ya que tienen un histograma asociado, es decir, estadísticas.
Respuestas:
SQL es un lenguaje declarativo, no un lenguaje de procedimiento. Es decir, construye una declaración SQL para describir los resultados que desea. No le está diciendo al motor SQL cómo hacer el trabajo.
Como regla general, es una buena idea dejar que el motor SQL y el optimizador SQL encuentren el mejor plan de consulta. Hay muchos años-persona de esfuerzo para desarrollar un motor SQL, así que deje que los ingenieros hagan lo que saben hacer.
Por supuesto, hay situaciones en las que el plan de consulta no es óptimo. Luego, desea usar sugerencias de consulta, reestructurar la consulta, actualizar estadísticas, usar tablas temporales, agregar índices, etc. para obtener un mejor rendimiento.
En cuanto a tu pregunta. El rendimiento de los CTE y las subconsultas debería, en teoría, ser el mismo, ya que ambos proporcionan la misma información al optimizador de consultas. Una diferencia es que un CTE usado más de una vez podría identificarse y calcularse fácilmente una vez. Los resultados podrían almacenarse y leerse varias veces. Desafortunadamente, SQL Server no parece aprovechar este método básico de optimización (podría llamarse a esto eliminación de subconsulta común).
Las tablas temporales son una cuestión diferente, ya que proporciona más orientación sobre cómo se debe ejecutar la consulta. Una diferencia importante es que el optimizador puede usar estadísticas de la tabla temporal para establecer su plan de consulta. Esto puede resultar en ganancias de rendimiento. Además, si tiene un CTE (subconsulta) complicado que se usa más de una vez, almacenarlo en una tabla temporal a menudo le dará un impulso al rendimiento. La consulta se ejecuta solo una vez.
La respuesta a su pregunta es que necesita jugar para obtener el rendimiento que espera, particularmente para consultas complejas que se ejecutan regularmente. En un mundo ideal, el optimizador de consultas encontraría la ruta de ejecución perfecta. Aunque a menudo lo hace, es posible que pueda encontrar una manera de obtener un mejor rendimiento.
fuente
No hay regla Encuentro que los CTE son más legibles y los uso a menos que que presenten algún problema de rendimiento, en cuyo caso investigo el problema real en lugar de adivinar que el CTE es el problema e intento volver a escribirlo con un enfoque diferente. Por lo general, el problema tiene más que la forma en que elegí declarar declarativamente mis intenciones con la consulta.
Ciertamente, hay casos en los que puede desentrañar CTE o eliminar subconsultas y reemplazarlas con una tabla #temp y reducir la duración. Esto puede deberse a varias cosas, como las estadísticas obsoletas, la incapacidad de obtener estadísticas precisas (por ejemplo, unirse a una función con valores de tabla), el paralelismo o incluso la incapacidad de generar un plan óptimo debido a la complejidad de la consulta ( en cuyo caso dividirlo puede darle al optimizador una oportunidad de lucha). Pero también hay casos en los que la E / S involucrada en la creación de una tabla #temp puede superar los otros aspectos de rendimiento que pueden hacer que una forma de plan particular usando un CTE sea menos atractiva.
Honestamente, hay demasiadas variables para proporcionar una respuesta "correcta" a su pregunta. No hay una forma predecible de saber cuándo una consulta puede inclinarse a favor de un enfoque u otro; solo sepa que, en teoría, la misma semántica para un CTE o una subconsulta única debería ejecutarse exactamente igual. Creo que su pregunta sería más valiosa si presenta algunos casos en los que esto no es cierto: puede ser que haya descubierto una limitación en el optimizador (o haya descubierto una conocida), o que sus consultas no sean semánticamente equivalentes o ese contiene un elemento que frustra la optimización.
Por lo tanto, sugeriría escribir la consulta de la manera que le parezca más natural, y solo se desviará cuando descubra un problema de rendimiento real que tiene el optimizador. Personalmente los clasifico CTE, luego subconsulta, con la tabla #temp como último recurso.
fuente
link / edit / close / flag
: si ha habido votos para cerrar la pregunta, veráclose (n)
dónden
representa el número de usuarios que votaron para cerrar su pregunta. Si hace clic en el enlace, verá los motivos que seleccionaron esos usuarios.#temp está materalizado y CTE no.
CTE es solo una sintaxis, por lo que en teoría es solo una subconsulta. Se ejecuta. #temp se materializa. Por lo tanto, un CTE costoso en una unión que se ejecuta muchas veces puede ser mejor en un #temp. Por otro lado, si se trata de una evaluación fácil que no se ejecuta, pero algunas veces no vale la pena la sobrecarga de #temp.
Hay algunas personas en SO a las que no les gusta la variable de tabla, pero me gustan porque se materializan y son más rápidas de crear que #temp. Hay momentos en que el optimizador de consultas funciona mejor con un #temp en comparación con una variable de tabla.
La capacidad de crear un PK en una variable #temp o table le da al optimizador de consultas más información que un CTE (ya que no puede declarar un PK en un CTE).
fuente
Solo 2 cosas que creo hacen SIEMPRE preferible usar una tabla # Temp en lugar de un CTE son:
No puede poner una clave primaria en un CTE, por lo que los datos a los que accede el CTE tendrán que atravesar cada uno de los índices en las tablas del CTE en lugar de simplemente acceder al PK o al Índice en la tabla temporal.
Debido a que no puede agregar restricciones, índices y claves primarias a un CTE, son más propensos a la aparición de errores y datos incorrectos.
-un día cuando ayer
Aquí hay un ejemplo en el que las restricciones #table pueden evitar datos incorrectos, que no es el caso en los CTE
fuente
ALWAYS
está un poco lejos pero gracias por la respuesta. En términos de legibilidad, el uso de CTE puede ser algo bueno.CHECK
restricción que se refiere a múltiples filas / tablas es No permitido). ¿Puede publicar un ejemplo donde un CTE exhiba un error que el equivalente de la tabla temporal no?