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 mirando 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).
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 una opción. En las funciones, por ejemplo, solo es posible usar una variable de tabla y si necesita escribir en la tabla en un ámbito secundario, solo una #temp
tabla lo hará (los parámetros con valores de tabla permiten acceso de solo lectura ).
Si tiene una opción, algunas sugerencias están a continuación (aunque el método más confiable es simplemente probar ambas con su carga de trabajo específica).
Si necesita un índice que no se puede crear en una variable de tabla, entonces, por supuesto, necesitará una #temporary
tabla. Sin embargo, los detalles de esto dependen de la versión. Para SQL Server 2012 y posteriores, los únicos índices que se podían crear en las variables de la tabla eran aquellos creados implícitamente mediante una restricción UNIQUE
o PRIMARY KEY
. SQL Server 2014 introdujo la sintaxis de índice en línea para un subconjunto de las opciones disponibles en CREATE INDEX
. Esto se ha extendido desde entonces para permitir condiciones de índice filtrado. INCLUDE
Sin embargo, todavía no es posible crear índices con columnas -d o índices de almacén de columnas en las variables de tabla.
Si va a agregar y eliminar repetidamente un gran número de filas de la tabla, use una #temporary
tabla. Eso es compatible TRUNCATE
(que es más eficiente que DELETE
para tablas grandes) y, además, las inserciones posteriores que siguen a TRUNCATE
pueden tener un mejor rendimiento que las que siguen a DELETE
como se ilustra aquí .
- 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 es capaz de usar el intercambio de conjuntos de filas (consulte "Efectos de compartir conjuntos de filas" a continuación para ver un ejemplo).
- Si el plan óptimo que usa la tabla variará dependiendo de los datos, use una
#temporary
tabla. Es compatible con la creación de estadísticas que permite que el plan se vuelva a compilar dinámicamente de acuerdo con los datos (aunque para las tablas temporales en caché en los procedimientos almacenados, el comportamiento de la compilación debe entenderse por separado).
- Si es poco probable que el plan óptimo para la consulta que usa la tabla cambie, entonces puede considerar una variable de tabla para omitir la sobrecarga de creación de estadísticas y recompilaciones (posiblemente requeriría sugerencias para arreglar el plan que desea).
- Si la fuente de los datos insertados en la tabla proviene de una
SELECT
declaración potencialmente costosa , entonces considere que usar una variable de tabla bloqueará la posibilidad de que esto use un plan paralelo.
- Si necesita los datos de la tabla para sobrevivir 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.
- Cuando se usa una
#temp
tabla dentro de un usuario, los bloqueos de transacciones pueden mantenerse 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 nivel de aislamiento) y también puede evitar el truncamiento del tempdb
registro de transacciones hasta que la transacción del usuario finaliza. Entonces esto podría favorecer el uso de variables de tabla.
- 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 la tabla en caché es menor que el de las
#temporary
tablas. Bob Ward señala en su tempdb
presentación que esto puede causar contención adicional en las tablas del sistema en condiciones de alta concurrencia. Además, cuando se trata con pequeñas cantidades de datos, esto puede marcar una diferencia apreciable en el rendimiento .
Efectos del intercambio de 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
tempDB
, que "en memoria" es un mito. Además: el optimizador de consultas siempre considerará que las variables de tabla contienen exactamente una fila; si tiene mucho más, esto puede conducir a planes de ejecución realmente malos.