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

298

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 tabla están en la memoria, es decir, el rendimiento de la variable de tabla es mejor que la tabla temporal porque la variable de tabla usa menos operaciones de E / S que la tabla temporal.

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

Pero no sé cuáles son los "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? ¿Hay alguna función o herramienta en SQL Server 2005 para medir la escala de la variable de la tabla o avisarme cuando la variable de la tabla se coloca en el disco desde la memoria?

yman
fuente
55
Casi siempre se encuentra una variable de tabla 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.
marc_s
Puede encontrar esta útil stackoverflow.com/questions/27894/…
Igor Borisenko
2
@marc_s: puede colocar el "casi" en esa declaración. Siempre está en tempdb(pero también puede estar completamente en la memoria)
Martin Smith
2
Con SQL 2014 ahora puede crear una variable de tabla en la memoria
paparazzo

Respuestas:

362

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

  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 posteriores, los únicos índices que se podían crear en las variables de la tabla eran aquellos creados implícitamente mediante una restricción UNIQUEo 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. INCLUDESin embargo, todavía no es posible crear índices con columnas -d o índices de almacén de columnas en las variables de tabla.

  2. Si va a agregar y eliminar repetidamente un gran número de filas de la tabla, use una #temporarytabla. Eso es compatible TRUNCATE(que 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 es capaz de usar el intercambio de conjuntos de filas (consulte "Efectos de compartir 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 una #temporarytabla. 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).
  5. 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).
  6. Si la fuente de los datos insertados en la tabla proviene de una SELECTdeclaración potencialmente costosa , entonces considere que usar una variable de tabla bloqueará la posibilidad de que esto use un plan paralelo.
  7. 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.
  8. Cuando se usa una #temptabla 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 tempdbregistro de transacciones hasta que la transacción del usuario finaliza. 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 la tabla en caché es menor que el de las #temporarytablas. 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 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
Martin Smith
fuente
2
Hola señor Martin Smith. En mi caso, solo quiero almacenar un conjunto de valores Ids para usarlos en otras consultas dentro del procedimiento Store. Entonces, ¿qué me recomiendan?
Jeancarlo Fontalvo
@JeancarloFontalvo, una variable de tabla con una clave principal idy uso OPTION (RECOMPILE)probablemente estaría bien para eso, pero pruebe ambos.
Martin Smith
¿Es la contención de metadatos la misma para la tabla temporal y la variable de tabla?
Syed Aqeel Ashiq
@Syed. Generalmente menos para TV. Los bloqueos se pueden liberar antes si dentro de una transacción de usuario. Vea también el enlace de Bob Ward.
Martin Smith
73

Use una variable de tabla si es para una cantidad muy pequeña de datos (miles de bytes)

Use una tabla temporal para muchos datos

Otra forma de pensarlo: si cree que podría beneficiarse de un índice, estadísticas automatizadas o cualquier bondad del optimizador de SQL, entonces su conjunto de datos es probablemente 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 ofrece 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.

Ábaco
fuente
La conclusión es que la variable de tabla está bien para conjuntos de datos pequeños, pero use la tabla temporal para conjuntos de datos más grandes. Tengo una consulta con miles de filas. Al cambiar de la tabla variable a la tabla temporal, el tiempo de consulta se reduce de 40 segundos a solo 5 segundos con todo lo demás igual.
liang
42

Microsoft dice aquí

Las variables de 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 asumiendo que la variable de tabla no tiene filas. Por esta razón, debe tener cuidado al usar una variable de tabla si espera un mayor número de filas (mayor que 100). Las tablas temporales pueden ser una mejor solución en este caso.

Paul Sturm
fuente
14

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

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

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

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


fuente
4

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

Para probar una tabla temporal:

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

Para probar una tabla de variables:

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

Algo más que he experimentado es: si su esquema no tiene GRANTprivilegios para crear tablas, use tablas variables.

Mina Gabriel
fuente
3

escribiendo datos en tablas declaradas declare @tby después de unirme a otras tablas, me di cuenta de que el tiempo de respuesta en comparación con las tablas temporalestempdb .. # tb es mucho mayor.

Cuando me uno a ellos con @tb, el tiempo es mucho más largo para devolver el resultado, a diferencia de #tm , el retorno es casi instantáneo.

Hice pruebas con una unión de 10,000 filas y una con otras 5 tablas

César Augusto
fuente
¿Podría publicar la prueba que realizó para obtener estas cifras?
Dan Def