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 frente a 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 frente a una tabla temporal local, no siempre tiene 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, solo un #temp
la tabla servirá (los parámetros con valores de tabla permiten acceso de solo lectura).
Donde tiene una opción, algunas sugerencias se encuentran a continuación (aunque el método más confiable es simplemente probar ambos con su carga de trabajo específica).
-
Si necesita un índice que no se puede crear en una variable de tabla, por supuesto necesitará un
#temporary
mesa. 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 aquellos creados implícitamente a través de unUNIQUE
oPRIMARY KEY
restricción. SQL Server 2014 introdujo la sintaxis de índice en línea para un subconjunto de las opciones disponibles enCREATE INDEX
. Esto se ha ampliado desde entonces para permitir condiciones de índice filtradas. Índices conINCLUDE
Sin embargo, todavía no es posible crear columnas -d o índices de almacén de columnas en variables de tabla. -
Si agregará y eliminará repetidamente una gran cantidad de filas de la tabla, use un
#temporary
mesa. Eso admiteTRUNCATE
(que es más eficiente queDELETE
para tablas grandes) y, además, inserciones posteriores después de unTRUNCATE
puede tener un mejor rendimiento que los que siguen unDELETE
como se ilustra aquí. - Si eliminará o actualizará una gran cantidad de filas, es posible que la tabla temporal funcione mucho mejor que una variable de tabla, si puede usar el uso compartido de conjuntos de filas (consulte "Efectos del uso compartido de conjuntos de filas" a continuación para ver un ejemplo) .
- Si el plan óptimo que usa la tabla variará dependiendo de los datos, use un
#temporary
mesa. Eso admite la creación de estadísticas que permiten que el plan se vuelva a compilar dinámicamente de acuerdo con los datos (aunque para las tablas temporales almacenadas en caché en los procedimientos almacenados, el comportamiento de la recompilación debe entenderse por separado). - Si es poco probable que cambie el plan óptimo para la consulta que usa la tabla, entonces puede considerar una variable de tabla para omitir la sobrecarga de creación de estadísticas y recompilaciones (posiblemente requiera sugerencias para arreglar el plan que desea).
- Si la fuente de los datos insertados en la tabla proviene de un
SELECT
potencialmente costoso entonces considere que usar una variable de tabla bloqueará la posibilidad de que esto use un plan paralelo. - Si necesita que los datos de la tabla sobrevivan a una reversión de una transacción de un 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 largo de SQL.
- Al usar un
#temp
la tabla dentro de los bloqueos de transacciones de un usuario se pueden mantener por más tiempo que para las variables de la tabla (potencialmente hasta el final de la transacción frente al final de la declaración dependiendo del tipo de bloqueo y el nivel de aislamiento) y también puede evitar el truncamiento detempdb
registro de transacciones hasta que finalice la transacción del usuario. Esto podría favorecer el uso de variables de tabla. - Dentro de las rutinas almacenadas, tanto las variables de tabla como las tablas temporales se pueden almacenar en caché. El mantenimiento de metadatos para las variables de la tabla en caché es menor que para
#temporary
mesas. Bob Ward señala en sutempdb
presentación de que esto puede causar una 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 medible en el rendimiento.
Efectos de compartir 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