Sobre la elección entre tablas temporales y variables de tabla en SQL

Es importante entender cuándo utilizar tablas temporales o variables de tabla para almacenar datos de manera temporal en SQL. Aunque ofrecen funciones similares, tienen características y escenarios de uso diferentes. En este artículo, explicamos en detalle las características de cada una y exploramos cómo elegir la mejor opción.

Índice

Características de las tablas temporales

Las tablas temporales son tablas que almacenan datos temporalmente en SQL y suelen utilizar los prefijos # o ##.

Cómo crearlas

Las tablas temporales se crean utilizando la sentencia CREATE TABLE. Por ejemplo:

CREATE TABLE #TempTable (
    ID INT,
    Name NVARCHAR(50)
);

Usos

Las tablas temporales son ideales cuando se necesita almacenar grandes volúmenes de datos temporalmente y reutilizarlos en varias sentencias.

Rendimiento

Dado que las tablas temporales almacenan datos en disco, pueden manejar grandes volúmenes de datos de manera estable, aunque son susceptibles al I/O de disco.

Ámbito

El ámbito de las tablas temporales está limitado a la sesión o lote en el que se crean, y se eliminan automáticamente al finalizar la sesión.

-- Ejemplo de uso en una sesión
INSERT INTO #TempTable (ID, Name) VALUES (1, 'Alice');
SELECT * FROM #TempTable;

Características de las variables de tabla

Las variables de tabla son tablas que se pueden utilizar como variables en SQL, principalmente para operaciones temporales con datos.

Cómo declararlas

Las variables de tabla se declaran con la sentencia DECLARE. Por ejemplo:

DECLARE @TableVar TABLE (
    ID INT,
    Name NVARCHAR(50)
);

Usos

Las variables de tabla son adecuadas para manejar pequeñas cantidades de datos o almacenar datos temporalmente dentro de un procedimiento almacenado.

Rendimiento

Las variables de tabla almacenan datos en la memoria, lo que las hace rápidas para pequeñas operaciones, pero no son adecuadas para manejar grandes volúmenes de datos.

Ámbito

El ámbito de una variable de tabla está limitado al lote o procedimiento almacenado en el que se declara, y se libera automáticamente al salir de dicho ámbito.

-- Ejemplo de uso en un lote
INSERT INTO @TableVar (ID, Name) VALUES (1, 'Alice');
SELECT * FROM @TableVar;

Comparación de rendimiento

El rendimiento de las tablas temporales y las variables de tabla varía según la cantidad de datos y las operaciones involucradas. A continuación, compararemos sus diferencias en rendimiento con ejemplos específicos.

Para pequeñas cantidades de datos

Las variables de tabla ofrecen un mejor rendimiento para operaciones con pequeñas cantidades de datos, ya que las operaciones se realizan en memoria y no hay sobrecarga de I/O de disco.

-- Ejemplo donde el rendimiento de las variables de tabla es superior
DECLARE @TableVar TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @TableVar (ID, Name) VALUES (1, 'Alice'), (2, 'Bob');
SELECT * FROM @TableVar;

Para grandes cantidades de datos

Para grandes volúmenes de datos, las tablas temporales son más adecuadas, ya que almacenan los datos en disco y permiten la creación de índices.

-- Ejemplo de uso de tablas temporales con grandes volúmenes de datos
CREATE TABLE #TempTable (ID INT, Name NVARCHAR(50));
INSERT INTO #TempTable (ID, Name)
SELECT ID, Name FROM LargeSourceTable;
CREATE INDEX idx_temp ON #TempTable(ID);
SELECT * FROM #TempTable;

Con o sin índices

Las tablas temporales permiten la creación de índices para mejorar el rendimiento de las consultas. En cambio, las variables de tabla tienen restricciones para crear índices, lo que afecta su rendimiento en consultas complejas.

Procesamiento de consultas complejas

Las tablas temporales ofrecen un rendimiento estable en consultas complejas y uniones. Las variables de tabla, por otro lado, no almacenan en caché los planes de consulta, lo que puede hacer que el rendimiento sea inferior en operaciones complejas.

-- Ejemplo de uso de una tabla temporal en consultas complejas
CREATE TABLE #TempTable (ID INT, Name NVARCHAR(50));
INSERT INTO #TempTable (ID, Name)
SELECT ID, Name FROM LargeSourceTable;
SELECT t1.ID, t2.Name
FROM #TempTable t1
JOIN AnotherTable t2 ON t1.ID = t2.ID;

Diferencias de ámbito y tiempo de vida

Las tablas temporales y las variables de tabla tienen diferentes ámbitos y tiempos de vida. Comprender estas diferencias es clave para seleccionar la opción adecuada.

Ámbito de las tablas temporales

Las tablas temporales son válidas dentro de la sesión o lote en que se crean. Se eliminan automáticamente al finalizar la sesión. Las tablas temporales locales (#TempTable) solo son accesibles desde la sesión actual, mientras que las globales (##TempTable) pueden ser accedidas desde otras sesiones.

-- Ejemplo del ámbito de una tabla temporal
CREATE TABLE #TempTable (ID INT, Name NVARCHAR(50));
-- La tabla #TempTable se eliminará automáticamente al finalizar la sesión

Ámbito de las variables de tabla

Las variables de tabla son válidas únicamente dentro del lote o procedimiento almacenado donde se declaran, y se liberan automáticamente al salir de su ámbito.

-- Ejemplo del ámbito de una variable de tabla
DECLARE @TableVar TABLE (ID INT, Name NVARCHAR(50));
-- La variable de tabla @TableVar se liberará al finalizar el lote

Diferencias en el tiempo de vida

El tiempo de vida de una tabla temporal depende de la duración de la sesión. Si la sesión se mantiene activa por mucho tiempo, la tabla temporal existirá durante ese tiempo. En cambio, las variables de tabla se liberan inmediatamente después de que el lote o el procedimiento almacenado que las declaró se complete.

Aplicaciones según el ámbito y tiempo de vida

Cuando se necesita compartir datos entre varios lotes o procedimientos almacenados a lo largo de una sesión, las tablas temporales son la mejor opción. Para almacenar datos temporalmente dentro de un solo lote o procedimiento, las variables de tabla son más prácticas.

-- Ejemplo de una tabla temporal
CREATE TABLE #SessionTemp (ID INT, Name NVARCHAR(50));
INSERT INTO #SessionTemp (ID, Name) VALUES (1, 'Alice');

-- Puede ser accedida desde otro lote o procedimiento almacenado
SELECT * FROM #SessionTemp;

-- Ejemplo de una variable de tabla
DECLARE @BatchVar TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @BatchVar (ID, Name) VALUES (1, 'Alice');
SELECT * FROM @BatchVar;
-- Se liberará al finalizar el lote

Escenarios donde aplican las tablas temporales y variables de tabla

Tanto las tablas temporales como las variables de tabla son la mejor opción en escenarios específicos. A continuación, describimos cuándo es mejor utilizar cada una.

Escenarios en los que las tablas temporales son adecuadas

Las tablas temporales son especialmente útiles en los siguientes casos:

Manejo de grandes volúmenes de datos

Son adecuadas para almacenar grandes volúmenes de datos temporalmente y realizar múltiples operaciones sobre esos datos. Dado que los datos se almacenan en disco, no están limitadas por la memoria.

CREATE TABLE #TempTable (ID INT, Name NVARCHAR(50));
INSERT INTO #TempTable (ID, Name) SELECT ID, Name FROM LargeTable;
SELECT * FROM #TempTable WHERE ID > 1000;

Creación de índices

Son adecuadas cuando se necesita crear índices para mejorar el rendimiento de las consultas.

CREATE TABLE #TempTable (ID INT, Name NVARCHAR(50));
INSERT INTO #TempTable (ID, Name) SELECT ID, Name FROM LargeTable;
CREATE INDEX idx_temp ON #TempTable(ID);
SELECT * FROM #TempTable WHERE ID > 1000;

Compartir datos entre sesiones

Cuando se necesita compartir datos a lo largo de una sesión entre varios procedimientos almacenados o lotes, las tablas temporales son la mejor opción.

CREATE TABLE #TempTable (ID INT, Name NVARCHAR(50));
INSERT INTO #TempTable (ID, Name) VALUES (1, 'Alice');
-- Puede ser accedida desde otro lote o procedimiento almacenado
SELECT * FROM #TempTable;

Escenarios en los que las variables de tabla son adecuadas

Las variables de tabla son especialmente útiles en los siguientes casos:

Manejo de pequeñas cantidades de datos

Son adecuadas para manejar pequeñas cantidades de datos. Como los datos se manejan en memoria, el procesamiento es rápido.

DECLARE @TableVar TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @TableVar (ID, Name) VALUES (1, 'Alice'), (2, 'Bob');
SELECT * FROM @TableVar;

Almacenamiento temporal de datos

Son adecuadas cuando se necesita almacenar datos temporalmente dentro de un único lote o procedimiento almacenado.

DECLARE @TableVar TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @TableVar (ID, Name) VALUES (1, 'Alice');
-- Se liberará al finalizar el lote
SELECT * FROM @TableVar;

Uso dentro de un trigger

Las variables de tabla también son adecuadas para almacenar datos temporalmente dentro de un trigger. Debido a su ámbito limitado, las variables de tabla ofrecen un enfoque ligero en estos casos.

CREATE TRIGGER trgAfterInsert ON SampleTable
AFTER INSERT AS
BEGIN
    DECLARE @InsertedData TABLE (ID INT, Name NVARCHAR(50));
    INSERT INTO @InsertedData (ID, Name)
    SELECT ID, Name FROM Inserted;
    -- Operación de datos dentro del trigger
    SELECT * FROM @InsertedData;
END;

Mejores prácticas en SQL

Presentamos algunas mejores prácticas para utilizar adecuadamente tablas temporales y variables de tabla, optimizando así el rendimiento y la eficiencia de las consultas SQL.

Elección según la cantidad de datos

Para pequeñas operaciones de datos, utiliza variables de tabla, y para grandes operaciones de datos, utiliza tablas temporales para optimizar el rendimiento.

-- Para pequeñas cantidades de datos, utiliza variables de tabla
DECLARE @SmallData TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @SmallData (ID, Name) VALUES (1, 'Alice'), (2, 'Bob');
SELECT * FROM @SmallData;

-- Para grandes cantidades de datos, utiliza tablas temporales
CREATE TABLE #LargeData (ID INT, Name NVARCHAR(50));
INSERT INTO #LargeData (ID, Name) SELECT ID, Name FROM LargeSourceTable;
SELECT * FROM #LargeData;

Uso de índices

Crear índices en tablas temporales puede mejorar el rendimiento de las consultas con grandes volúmenes de datos.

CREATE TABLE #IndexedTable (ID INT, Name NVARCHAR(50));
INSERT INTO #IndexedTable (ID, Name) SELECT ID, Name FROM LargeSourceTable;
CREATE INDEX idx_temp ON #IndexedTable(ID);
SELECT * FROM #IndexedTable WHERE ID > 1000;

Diseño consciente del ámbito

Ser consciente del ámbito y tiempo de vida de los datos evitará el uso innecesario de recursos.

-- Para datos que se utilizarán durante toda la sesión, utiliza tablas temporales
CREATE TABLE #SessionData (ID INT, Name NVARCHAR(50));
INSERT INTO #SessionData (ID, Name) VALUES (1, 'Alice');
-- Puede ser accedida fuera del lote actual
SELECT * FROM #SessionData;

-- Para datos que solo se usarán en un lote, utiliza variables de tabla
DECLARE @BatchData TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @BatchData (ID, Name) VALUES (1, 'Alice');
-- Se liberará al finalizar el lote
SELECT * FROM @BatchData;

Facilidad de mantenimiento

Las variables de tabla se liberan automáticamente al finalizar el lote, lo que evita fugas de memoria y facilita su mantenimiento, especialmente dentro de procedimientos almacenados.

-- Ejemplo de uso de una variable de tabla en un procedimiento almacenado
CREATE PROCEDURE SampleProcedure
AS
BEGIN
    DECLARE @ProcData TABLE (ID INT, Name NVARCHAR(50));
    INSERT INTO @ProcData (ID, Name) VALUES (1, 'Alice');
    SELECT * FROM @ProcData;
END;

Pruebas y monitoreo del rendimiento

Es importante realizar pruebas y monitorear el rendimiento en cada escenario para hacer la elección más adecuada.

-- Realiza pruebas en escenarios reales
-- Usa herramientas de monitoreo de rendimiento para verificar la eficiencia

Conclusión

Resumimos los puntos clave para utilizar tablas temporales y variables de tabla de manera eficaz.

Las tablas temporales son ideales para manejar grandes volúmenes de datos o cuando se necesita crear índices y compartir datos entre varias sesiones. Las variables de tabla, por su parte, son adecuadas para operaciones rápidas con pequeñas cantidades de datos o para almacenar datos temporalmente en un lote. Seleccionar la herramienta adecuada según el escenario maximizará el rendimiento de tus consultas SQL.

Índice