¿Cuándo debo usar una variable de tabla frente a una tabla temporal en el servidor SQL?

Resuelto yman asked hace 12 años • 6 respuestas

Estoy aprendiendo más detalles en la variable de tabla. Dice que las tablas temporales siempre están en el disco y las variables de la tabla están en la memoria, es decir, el rendimiento de la variable de la tabla es mejor que el de la tabla temporal porque la variable de la tabla utiliza menos operaciones de E/S que la tabla temporal.

Pero a veces, si hay demasiados registros en una variable de tabla que no se pueden contener en la memoria, la variable de tabla se guardará en el disco como la tabla temporal.

Pero no sé qué es "demasiados registros". ¿100.000 registros? o 1000.000 registros? ¿Cómo puedo saber si una variable de tabla que estoy usando está en la memoria o en el disco? ¿Existe alguna función o herramienta en SQL Server 2005 para medir la escala de la variable de la tabla o para informarme cuándo la variable de la tabla se guarda en el disco desde la memoria?

yman avatar Aug 08 '12 11:08 yman
Aceptado

Su pregunta muestra que ha sucumbido a algunos de los conceptos erróneos comunes que rodean las variables de tabla y las tablas temporales.

He escrito una respuesta bastante extensa en el sitio de DBA analizando las diferencias entre los dos tipos de objetos. Esto también responde a su pregunta sobre el disco y la memoria (no vi ninguna diferencia significativa en el comportamiento entre los dos).

Sin embargo, con respecto a la pregunta en el título sobre cuándo usar una variable de tabla versus una tabla temporal local, no siempre tienes otra opción. En funciones, por ejemplo, solo es posible usar una variable de tabla y si necesita escribir en la tabla en un ámbito secundario, entonces solo una #temptabla servirá (los parámetros con valores de tabla permiten acceso de solo lectura ).

A continuación se presentan algunas sugerencias sobre dónde tiene opciones (aunque el método más confiable es simplemente probar ambos con su carga de trabajo específica).

  1. Si necesita un índice que no se puede crear en una variable de tabla, entonces, por supuesto, necesitará una #temporarytabla. Sin embargo, los detalles de esto dependen de la versión. Para SQL Server 2012 y versiones anteriores, los únicos índices que se podían crear en las variables de la tabla eran los creados implícitamente mediante una restricción UNIQUEo . PRIMARY KEYSQL Server 2014 introdujo la sintaxis de índice en línea para un subconjunto de las opciones disponibles en CREATE INDEX. Esto se ha ampliado desde entonces para permitir condiciones de índice filtradas. INCLUDESin embargo, todavía no es posible crear índices con columnas -d o índices de almacén de columnas en variables de tabla.

  2. Si va a agregar y eliminar repetidamente una gran cantidad de filas de la tabla, utilice una #temporarytabla. Eso admite TRUNCATE(lo cual es más eficiente que DELETEpara tablas grandes) y, además, las inserciones posteriores que siguen a TRUNCATEpueden tener un mejor rendimiento que las que siguen a DELETE como se ilustra aquí .

  3. Si va a eliminar o actualizar una gran cantidad de filas, entonces la tabla temporal puede funcionar mucho mejor que una variable de tabla, si puede utilizar el uso compartido de conjuntos de filas (consulte "Efectos del uso compartido de conjuntos de filas" a continuación para ver un ejemplo).
  4. Si el plan óptimo que utiliza la tabla varía según los datos, utilice una #temporarytabla. Esto admite la creación de estadísticas que permiten que el plan se recopile dinámicamente de acuerdo con los datos (aunque para las tablas temporales almacenadas en caché en procedimientos almacenados, el comportamiento de recompilación debe entenderse por separado).
  5. Si es poco probable que el plan óptimo para la consulta que utiliza la tabla cambie alguna vez, entonces puede considerar una variable de tabla para evitar la sobrecarga de la creación y recompilación de estadísticas (posiblemente requeriría sugerencias para arreglar el plan que desea).
  6. Si la fuente de los datos insertados en la tabla proviene de una SELECTdeclaración potencialmente costosa, considere que el uso de una variable de tabla bloqueará la posibilidad de que se utilice un plan paralelo.
  7. Si necesita que los datos de la tabla sobrevivan a una reversión de una transacción de usuario externo, utilice una variable de tabla. Un posible caso de uso para esto podría ser registrar el progreso de diferentes pasos en un lote SQL largo.
  8. Cuando se utiliza una #temptabla dentro de un usuario, los bloqueos de transacciones se pueden mantener por más tiempo que para las variables de la tabla (potencialmente hasta el final de la transacción versus el final de la declaración dependiendo del tipo de bloqueo y el nivel de aislamiento) y también puede evitar el truncamiento del tempdbregistro de transacciones hasta el finaliza la transacción del usuario. Entonces esto podría favorecer el uso de variables de tabla.
  9. Dentro de las rutinas almacenadas, se pueden almacenar en caché tanto las variables de tabla como las tablas temporales. El mantenimiento de metadatos para las variables de tablas almacenadas en caché es menor que el de #temporarylas tablas. Bob Ward señala en su tempdbpresentación que esto puede causar contención adicional en las tablas del sistema en condiciones de alta concurrencia. Además, cuando se trata de pequeñas cantidades de datos, esto puede marcar una diferencia mensurable en el rendimiento .

Efectos de compartir conjuntos de filas

DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);

CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);

INSERT INTO @T 
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2

SET STATISTICS TIME ON

/*CPU time = 7016 ms,  elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;

/*CPU time = 6234 ms,  elapsed time = 7236 ms.*/
DELETE FROM @T

/* CPU time = 828 ms,  elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;

/*CPU time = 672 ms,  elapsed time = 980 ms.*/
DELETE FROM #T

DROP TABLE #T
Martin Smith avatar Dec 08 '2012 13:12 Martin Smith

Utilice una variable de tabla si se trata de una cantidad muy pequeña de datos (miles de bytes)

Utilice una tabla temporal para una gran cantidad de datos

Otra forma de pensarlo: si cree que podría beneficiarse de un índice, estadísticas automatizadas o cualquier optimizador de SQL, entonces su conjunto de datos probablemente sea demasiado grande para una variable de tabla.

En mi ejemplo, solo quería poner unas 20 filas en un formato y modificarlas como un grupo, antes de usarlas para ACTUALIZAR/INSERTAR una tabla permanente. Entonces una variable de tabla es perfecta.

Pero también estoy ejecutando SQL para rellenar miles de filas a la vez, y definitivamente puedo decir que las tablas temporales funcionan mucho mejor que las variables de tabla.

Esto no es diferente a cómo los CTE son una preocupación por una razón de tamaño similar: si los datos en el CTE son muy pequeños, encuentro que un CTE funciona tan bien o mejor que lo que genera el optimizador, pero si es bastante grande, entonces te duele mucho.

Mi comprensión se basa principalmente en http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/ , que tiene muchos más detalles.

Abacus avatar Jan 22 '2013 18:01 Abacus

Microsoft dice aquí

Las variables de la tabla no tienen estadísticas de distribución, no activarán recompilaciones. Por lo tanto, en muchos casos, el optimizador creará un plan de consulta suponiendo que la variable de la tabla no tiene filas. Por este motivo, debe tener cuidado al utilizar una variable de tabla si espera un número mayor de filas (más de 100). Las tablas temporales pueden ser una mejor solución en este caso.

Paul Sturm avatar Feb 26 '2014 19:02 Paul Sturm

Estoy totalmente de acuerdo con Abacus (lo siento, no tengo suficientes puntos para comentar).

Además, tenga en cuenta que no todo se reduce necesariamente a cuántos registros tiene, sino al tamaño de sus registros.

Por ejemplo, ¿ha considerado la diferencia de rendimiento entre 1000 registros con 50 columnas cada uno y 100 000 registros con solo 5 columnas cada uno?

Por último, ¿quizás esté consultando/almacenando más datos de los que necesita? Aquí hay una buena lectura sobre estrategias de optimización de SQL . Limite la cantidad de datos que está extrayendo, especialmente si no los está usando todos (algunos programadores de SQL se vuelven perezosos y simplemente seleccionan todo aunque solo usan un pequeño subconjunto). No olvide que el analizador de consultas SQL también puede convertirse en su mejor amigo.

 avatar Jul 07 '2014 03:07

La tabla de variables está disponible solo para la sesión actual, por ejemplo, si necesita EXECotro procedimiento almacenado dentro de la actual tendrá que pasar la tabla Table Valued Parametery por supuesto esto afectará el rendimiento, con tablas temporales puede hacer esto solo pasando el nombre de la tabla temporal

Para probar una tabla temporal:

  • Editor de consultas de estudio de gestión abierto
  • Crear una tabla temporal
  • Abrir otra ventana del editor de consultas
  • Seleccione de esta tabla "Disponible"

Para probar una tabla de variables:

  • Editor de consultas de estudio de gestión abierto
  • Crear una tabla de variables
  • Abrir otra ventana del editor de consultas
  • Seleccione de esta tabla "No disponible"

Otra cosa que he experimentado es: si su esquema no tiene GRANTprivilegios para crear tablas, utilice tablas de variables.

Mina Gabriel avatar Jul 06 '2016 16:07 Mina Gabriel