sql >> Base de Datos >  >> RDS >> Sqlserver

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

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).

  1. 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 un UNIQUE o PRIMARY KEY restricción. SQL 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. Índices con INCLUDE Sin embargo, todavía no es posible crear columnas -d o índices de almacén de columnas en variables de tabla.

  2. Si agregará y eliminará repetidamente una gran cantidad de filas de la tabla, use un #temporary mesa. Eso admite TRUNCATE (que es más eficiente que DELETE para tablas grandes) y, además, inserciones posteriores después de un TRUNCATE puede tener un mejor rendimiento que los que siguen un DELETE como se ilustra aquí.

  3. 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) .
  4. 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).
  5. 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).
  6. 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.
  7. 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.
  8. 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 de tempdb registro de transacciones hasta que finalice la transacción del usuario. Esto podría favorecer el uso de variables de tabla.
  9. 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 su tempdb 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