¿Cuál es la diferencia entre un CTE y una tabla temporal?

174

¿Cuál es la diferencia entre una expresión de tabla común (CTE) y una tabla temporal? ¿Y cuándo debo usar uno sobre el otro?

CTE

WITH cte (Column1, Column2, Column3)
AS
(
    SELECT Column1, Column2, Column3
    FROM SomeTable
)

SELECT * FROM cte

Tabla de temperatura

SELECT Column1, Column2, Column3
INTO #tmpTable
FROM SomeTable

SELECT * FROM #tmpTable
Rachel
fuente

Respuestas:

200

Esto es bastante amplio, pero le daré una respuesta lo más general posible.

CTE ...

  • No son indexables (pero pueden usar índices existentes en objetos referenciados)
  • No puede tener restricciones
  • Son esencialmente desechables VIEWs
  • Persistir solo hasta que se ejecute la siguiente consulta
  • Puede ser recursivo
  • No tiene estadísticas dedicadas (confíe en las estadísticas de los objetos subyacentes)

#Tablas de temperatura ...

  • Son tablas materializadas reales que existen en tempdb
  • Puede ser indexado
  • Puede tener restricciones
  • Persistir por la vida de la CONEXIÓN actual
  • Puede ser referenciado por otras consultas o subprocedimientos
  • Tener estadísticas dedicadas generadas por el motor

En cuanto a cuándo usar cada uno, tienen casos de uso muy diferentes. Si va a tener un conjunto de resultados muy grande, o necesita referirse a él más de una vez, póngalo en una #temptabla. Si necesita ser recursivo, es desechable o es simplemente para simplificar algo lógicamente, CTEse prefiere a.

Además, una CTEdebe nunca serán usados para el rendimiento . Casi nunca acelerarás las cosas usando un CTE, porque, de nuevo, es solo una vista desechable. Puede hacer algunas cosas interesantes con ellos, pero acelerar una consulta no es realmente una de ellas.

JNK
fuente
acelerar un gran MERGE usando CTE es una cosa
AgentFire
1
Acelerar muchas consultas utilizando CTE también es una cosa porque con los CTE puede agregar su propio conocimiento comercial para superar el optimizador de consultas. Por ejemplo, puede hacer que la parte 1 de su CTE seleccione de las tablas donde sabe que las filas resultantes serán muy pequeñas. Dentro de la misma consulta, puede unir este pequeño conjunto de resultados a un conjunto de resultados más grande y omitir por completo los problemas causados ​​por estadísticas obsoletas, etc. Para hacer esto, debe agregar sugerencias de consulta para forzar el orden. Funciona, mejora el rendimiento.
Dave Hilditch
"nunca se utilizará para el rendimiento" es una declaración amplia y algo subjetiva, aunque entiendo su punto. Aunque, además de los otros comentarios, puede producirse otra ganancia de rendimiento potencial al usar un CTE al cambiar a un CTE recursivo desde otra forma de recursión, como llamadas a procedimientos recursivos o un cursor.
JD
29

EDITAR:

Por favor, vea los comentarios de Martin a continuación:

El CTE no se materializa como una tabla en la memoria. Es solo una forma de encapsular una definición de consulta. En el caso del OP, estará en línea y será lo mismo que hacer SELECT Column1, Column2, Column3 FROM SomeTable. La mayoría de las veces no se materializan por adelantado, por lo que esto no devuelve filas WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, también verifique los planes de ejecución. Aunque a veces es posible hackear el plan para obtener un carrete. Hay un elemento de conexión que solicita una pista para esto. - Martin Smith 15 de febrero de 12 a las 17:08


Respuesta original

CTE

Leer más en MSDN

Un CTE crea la tabla que se usa en la memoria, pero solo es válida para la consulta específica que le sigue. Cuando se utiliza la recursividad, esta puede ser una estructura efectiva.

También es posible que desee considerar el uso de una variable de tabla. Esto se usa como una tabla temporal y se puede usar varias veces sin necesidad de volver a materializarse para cada unión. Además, si necesita conservar algunos registros ahora, agregue algunos registros más después de la siguiente selección, agregue algunos registros más después de otra operación, luego devuelva esos pocos registros, entonces esta puede ser una estructura práctica, ya que no No es necesario dejarlo caer después de la ejecución. Principalmente solo azúcar sintáctico. Sin embargo, si mantiene bajo el recuento de filas, nunca se materializa en el disco. Consulte ¿Cuál es la diferencia entre una tabla temporal y una variable de tabla en SQL Server? para más detalles.

Tabla de temperatura

Lea más en MSDN: desplácese hacia abajo aproximadamente el 40% del camino

Una tabla temporal es literalmente una tabla creada en el disco, solo en una base de datos específica que todos saben que se puede eliminar. Es responsabilidad de un buen desarrollador destruir esas tablas cuando ya no son necesarias, pero un DBA también puede borrarlas.

Las tablas temporales vienen en dos variedades: local y global. En términos de MS Sql Server, utiliza una #tableNamedesignación para local y una ##tableNamedesignación para global (tenga en cuenta el uso de un solo o doble # como característica de identificación).

Tenga en cuenta que con las tablas temporales, a diferencia de las variables de tabla o CTE, puede aplicar índices y similares, ya que estas son legítimamente tablas en el sentido normal de la palabra.


En general, usaría tablas temporales para consultas más largas o más grandes, y CTE o variables de tabla si ya tuviera un conjunto de datos pequeño y quisiera escribir rápidamente un poco de código para algo pequeño. La experiencia y los consejos de otros indican que debe usar CTE donde tiene un pequeño número de filas devueltas. Si tiene un gran número, probablemente se beneficiaría de la capacidad de indexar en la tabla temporal.

jcolebrand
fuente
11
El CTE no se materializa como una tabla en la memoria. Es solo una forma de encapsular una definición de consulta. En el caso del OP, estará en línea y será lo mismo que hacerSELECT Column1, Column2, Column3 FROM SomeTable
Martin Smith
44
La mayoría de las veces no se materializan por adelantado, por lo que esto no devuelve filas WITH T(X) AS (SELECT NEWID())SELECT * FROM T T1 JOIN T T2 ON T1.X=T2.X, también verifique los planes de ejecución. Aunque a veces es posible hackear el plan para obtener un carrete. Hay un elemento de conexión que solicita una pista para esto.
Martin Smith
16

La respuesta aceptada aquí dice que "un CTE nunca debe usarse para el rendimiento", pero eso podría inducir a error. En el contexto de CTE versus tablas temporales, acabo de terminar de eliminar una gran cantidad de basura de un conjunto de procesos almacenados porque algunos tontos deben haber pensado que había poca o ninguna sobrecarga al usar tablas temporales. Metí el lote en los CTE, excepto aquellos que legítimamente iban a ser reutilizados durante todo el proceso. Obtuve aproximadamente un 20% de rendimiento en todas las métricas. Luego me puse a eliminar todos los cursores que intentaban implementar el procesamiento recursivo. Aquí fue donde vi la mayor ganancia. Terminé recortando los tiempos de respuesta por un factor de diez.

Los CTE y las tablas temporales tienen casos de uso muy diferentes. Solo quiero enfatizar que, aunque no es una panacea, la comprensión y el uso correcto de los CTE pueden conducir a algunas mejoras verdaderamente estelares tanto en la calidad / mantenimiento del código como en la velocidad. Desde que los manejé, veo las tablas temporales y los cursores como los grandes males del procesamiento de SQL. Puedo pasar bien con las variables de tabla y CTE para casi todo ahora. Mi código es más limpio y rápido.

Mel Padden
fuente
Ahora, seamos justos: los cursores son el gran mal; las tablas temporales son, en el peor de los casos, un mal menor . :-) Es realmente injusto ponerlos al mismo nivel, como te viste a ti mismo.
RDFozz
@RDFozz bien, el infierno tiene 9 círculos como todos sabemos . Pongamos tablas temporales en el 2 ° y cursores en ... 7 °? ;)
ypercubeᵀᴹ
1
¿Sabes cuál es el "gran mal" en la programación? Cuando la gente dice que una técnica en particular es malvada. Hay un lugar para cursores. Pueden superar a otras técnicas en ciertos escenarios. Aquí no hay maldad : debes aprender a usar la herramienta adecuada para el trabajo. Mide lo que estás haciendo y no creas la exageración de que los CTE, las tablas temporales o los cursores son malos. Medida: porque la verdad depende del escenario.
Dave Hilditch
@DaveHilditch es un comentario justo, pero también es un comentario justo para afirmar que en muchas, muchas situaciones, los cursores no son la solución correcta, por lo que es una generalización práctica tenerlos, como casi un último recurso.
Mel Padden
1
En mi experiencia, un CURSOR no es malo en sí mismo. Los CURSORES son comúnmente utilizados "erróneamente" por los desarrolladores porque en la mayoría de los lenguajes de programación, tienes que pensar de forma iterativa, a diferencia de SQL, donde debes pensar en lotes. Sé que este es un error común en mi lugar de trabajo, donde los desarrolladores simplemente no pueden "ver" una solución a un problema que no sea con un CURSOR, por lo tanto, un buen DBA es útil para enseñar y corregirlos. @DaveHilditch tiene toda la razón: la herramienta adecuada para el trabajo correcto es todo lo que se necesita.
Philippe
14

Se puede llamar a un CTE repetidamente dentro de una consulta y se evalúa cada vez que se hace referencia a él; este proceso puede ser recursivo. Si solo se hace referencia una vez, se comporta como una subconsulta, aunque los CTE se pueden parametrizar.

Una tabla temporal persiste físicamente y puede indexarse. En la práctica, el optimizador de consultas también puede persistir resultados intermedios de unión o subconsulta en segundo plano, como en operaciones de spool, por lo que no es estrictamente cierto que los resultados de los CTE nunca se conserven en el disco.

Las variables de la tabla IIRC (por otro lado) son siempre estructuras en memoria.

Preocupado por TunbridgeWells
fuente
44
Los CTE se pueden parametrizar? ¿Cómo? Además, las variables de tabla no siempre son estructuras en memoria. Vea la excelente respuesta de Martin a una pregunta relacionada.
Paul White
11

La tabla temporal es un objeto real en tempdb, pero cte es solo una especie de contenedor alrededor de consultas complejas para simplificar la sintaxis de la recursividad organizada en un solo paso.

Oleg Dok
fuente
8

La razón principal para usar CTE es acceder a las funciones de la ventana, como row_number()y varias otras.

Esto significa que puede hacer cosas como obtener la primera o la última fila por grupo MUY MUY MUY rápido y eficiente, más eficiente que otros medios en la mayoría de los casos prácticos .

with reallyfastcte as (
select *, 
row_number() over (partition by groupingcolumn order by sortingcolumn) as rownum
from sometable
)
select *
from reallyfastcte
where rownum = 1;

Puede ejecutar una consulta similar a la anterior utilizando una subconsulta correlacionada o utilizando una subconsulta, pero el CTE será más rápido en casi todos los escenarios.

Además, los CTE realmente pueden ayudar a simplificar su código. Esto puede generar ganancias de rendimiento porque comprende mejor la consulta y puede introducir más lógica de negocios para ayudar al optimizador a ser más selectivo.

Además, los CTE pueden aumentar el rendimiento si comprende su lógica empresarial y sabe qué partes de la consulta deben ejecutarse primero; por lo general, coloque primero sus consultas más selectivas que conducen a conjuntos de resultados que pueden usar un índice en su próxima unión y agregar la option(force order)consulta insinuación

Finalmente, los CTE no usan tempdb de forma predeterminada, por lo que reduce la contención en ese cuello de botella a través de su uso.

Las tablas temporales se deben usar si necesita consultar los datos varias veces, o alternativamente si mide sus consultas y descubre eso al insertarlas en una tabla temporal y luego agregar un índice para mejorar su rendimiento.

Dave Hilditch
fuente
todos los puntos buenos ... +1
Mel Padden
6

Parece que hay un poco de negatividad aquí hacia los CTE.

Entiendo que un CTE es básicamente una especie de vista ad hoc. SQL es tanto un lenguaje declarativo como un lenguaje basado en conjuntos. ¡Los CTE son una excelente manera de declarar un conjunto! ¡No poder indexar un CTE es realmente algo bueno porque no es necesario! Realmente es una especie de azúcar sintáctica para facilitar la lectura / escritura de la consulta. Cualquier optimizador decente resolverá el mejor plan de acceso utilizando índices en las tablas subyacentes. Esto significa que podría acelerar de manera efectiva su consulta CTE siguiendo los consejos del índice en las tablas subyacentes.

Además, solo porque haya definido un conjunto como CTE, no significa que todas las filas del conjunto deban procesarse. Dependiendo de la consulta, el optimizador puede procesar filas "suficientes" para satisfacer la consulta. Tal vez solo necesitabas los primeros 20 más o menos para tu pantalla. Si creó una tabla temporal, ¡realmente necesita leer / escribir todas esas filas!

Basado en esto, diría que los CTE son una gran característica de SQL y se pueden usar en cualquier lugar que faciliten la lectura de la consulta. Solo pensaría en una tabla temporal para un proceso por lotes que realmente necesitaría procesar cada registro. Incluso entonces afaik no se recomienda realmente porque en una tabla temporal es mucho más difícil para la base de datos ayudarlo con el almacenamiento en caché y los índices. Sería mejor tener una tabla permanente con un campo PK exclusivo para su transacción.

Tengo que admitir que mi experiencia es principalmente con DB2, así que supongo que CTE funciona de manera similar en ambos productos. Estaré felizmente corregido si los CTE son de alguna manera inferiores en el servidor SQL. ;)

Ben Thurley
fuente