Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
Este artículo contiene instrucciones esenciales para usar tablas temporales y resalta los principios de las tablas temporales de nivel de sesión.
El uso de la información de este artículo puede ayudarle a modularizar el código, lo que mejora tanto la reutilización como la facilidad de mantenimiento.
¿Qué son las tablas temporales?
Las tablas temporales son útiles al procesar datos, especialmente durante la transformación en las que los resultados intermedios son transitorios. En el grupo de SQL dedicado, existen tablas temporales en el nivel de sesión.
Las tablas temporales solo son visibles para la sesión en la que se crearon y se quitan automáticamente cuando se cierra esa sesión.
Las tablas temporales ofrecen una ventaja de rendimiento porque sus resultados se escriben en el almacenamiento local en lugar de en el almacenamiento remoto.
Tablas temporales en un grupo de SQL dedicado
En el recurso del grupo de SQL dedicado, las tablas temporales ofrecen una ventaja de rendimiento porque sus resultados se escriben en local en lugar de en almacenamiento remoto.
Creación de una tabla temporal
Las tablas temporales se crean mediante el prefijo del nombre de la tabla con un #. Por ejemplo:
CREATE TABLE #stats_ddl
(
[schema_name] NVARCHAR(128) NOT NULL
, [table_name] NVARCHAR(128) NOT NULL
, [stats_name] NVARCHAR(128) NOT NULL
, [stats_is_filtered] BIT NOT NULL
, [seq_nmbr] BIGINT NOT NULL
, [two_part_name] NVARCHAR(260) NOT NULL
, [three_part_name] NVARCHAR(400) NOT NULL
)
WITH
(
DISTRIBUTION = HASH([seq_nmbr])
, HEAP
)
Las tablas temporales también se pueden crear con un CTAS mediante exactamente el mismo enfoque:
CREATE TABLE #stats_ddl
WITH
(
DISTRIBUTION = HASH([seq_nmbr])
, HEAP
)
AS
(
SELECT
sm.[name] AS [schema_name]
, tb.[name] AS [table_name]
, st.[name] AS [stats_name]
, st.[has_filter] AS [stats_is_filtered]
, ROW_NUMBER()
OVER(ORDER BY (SELECT NULL)) AS [seq_nmbr]
, QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name]) AS [two_part_name]
, QUOTENAME(DB_NAME())+'.'+QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name]) AS [three_part_name]
FROM sys.objects AS ob
JOIN sys.stats AS st ON ob.[object_id] = st.[object_id]
JOIN sys.stats_columns AS sc ON st.[stats_id] = sc.[stats_id]
AND st.[object_id] = sc.[object_id]
JOIN sys.columns AS co ON sc.[column_id] = co.[column_id]
AND sc.[object_id] = co.[object_id]
JOIN sys.tables AS tb ON co.[object_id] = tb.[object_id]
JOIN sys.schemas AS sm ON tb.[schema_id] = sm.[schema_id]
WHERE 1=1
AND st.[user_created] = 1
GROUP BY
sm.[name]
, tb.[name]
, st.[name]
, st.[filter_definition]
, st.[has_filter]
)
;
Nota:
CTAS es un comando eficaz y tiene la ventaja adicional de ser eficiente en su uso del espacio del registro de transacciones.
Eliminar tablas temporales
Cuando se crea una nueva sesión, no debe existir ninguna tabla temporal.
Si va a llamar al mismo procedimiento almacenado, lo que crea un archivo temporal con el mismo nombre, para tener la seguridad de que las instrucciones CREATE TABLE se ejecutan correctamente, se puede usar una sencilla comprobación de existencia previa con DROP, como en el ejemplo siguiente:
IF OBJECT_ID('tempdb..#stats_ddl') IS NOT NULL
BEGIN
DROP TABLE #stats_ddl
END
Para codificar la coherencia, se recomienda usar este patrón para tablas y tablas temporales. También es recomendable usar DROP TABLE para quitar tablas temporales cuando haya terminado con ellas en el código.
En el desarrollo de procedimientos almacenados, es habitual ver los comandos drop agrupados al final de un procedimiento para asegurarse de que estos objetos se eliminen.
DROP TABLE #stats_ddl
Modularización de código
Dado que las tablas temporales se pueden ver en cualquier lugar de una sesión de usuario, esta funcionalidad se puede aprovechar para ayudarle a modular el código de la aplicación.
Por ejemplo, el siguiente procedimiento almacenado genera DDL para actualizar todas las estadísticas de la base de datos por nombre estadístico:
CREATE PROCEDURE [dbo].[prc_sqldw_update_stats]
( @update_type tinyint -- 1 default 2 fullscan 3 sample 4 resample
,@sample_pct tinyint
)
AS
IF @update_type NOT IN (1,2,3,4)
BEGIN;
THROW 151000,'Invalid value for @update_type parameter. Valid range 1 (default), 2 (fullscan), 3 (sample) or 4 (resample).',1;
END;
IF @sample_pct IS NULL
BEGIN;
SET @sample_pct = 20;
END;
IF OBJECT_ID('tempdb..#stats_ddl') IS NOT NULL
BEGIN
DROP TABLE #stats_ddl
END
CREATE TABLE #stats_ddl
WITH
(
DISTRIBUTION = HASH([seq_nmbr])
)
AS
(
SELECT
sm.[name] AS [schema_name]
, tb.[name] AS [table_name]
, st.[name] AS [stats_name]
, st.[has_filter] AS [stats_is_filtered]
, ROW_NUMBER()
OVER(ORDER BY (SELECT NULL)) AS [seq_nmbr]
, QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name]) AS [two_part_name]
, QUOTENAME(DB_NAME())+'.'+QUOTENAME(sm.[name])+'.'+QUOTENAME(tb.[name]) AS [three_part_name]
FROM sys.objects AS ob
JOIN sys.stats AS st ON ob.[object_id] = st.[object_id]
JOIN sys.stats_columns AS sc ON st.[stats_id] = sc.[stats_id]
AND st.[object_id] = sc.[object_id]
JOIN sys.columns AS co ON sc.[column_id] = co.[column_id]
AND sc.[object_id] = co.[object_id]
JOIN sys.tables AS tb ON co.[object_id] = tb.[object_id]
JOIN sys.schemas AS sm ON tb.[schema_id] = sm.[schema_id]
WHERE 1=1
AND st.[user_created] = 1
GROUP BY
sm.[name]
, tb.[name]
, st.[name]
, st.[filter_definition]
, st.[has_filter]
)
SELECT
CASE @update_type
WHEN 1
THEN 'UPDATE STATISTICS '+[two_part_name]+'('+[stats_name]+');'
WHEN 2
THEN 'UPDATE STATISTICS '+[two_part_name]+'('+[stats_name]+') WITH FULLSCAN;'
WHEN 3
THEN 'UPDATE STATISTICS '+[two_part_name]+'('+[stats_name]+') WITH SAMPLE '+CAST(@sample_pct AS VARCHAR(20))+' PERCENT;'
WHEN 4
THEN 'UPDATE STATISTICS '+[two_part_name]+'('+[stats_name]+') WITH RESAMPLE;'
END AS [update_stats_ddl]
, [seq_nmbr]
FROM #stats_ddl
;
GO
En esta fase, la única acción que se ha producido es la creación de un procedimiento almacenado que genera una tabla temporal, #stats_ddl, con instrucciones DDL.
Este procedimiento almacenado quita un existente #stats_ddl para asegurarse de que no se produce un error si se ejecuta más de una vez dentro de una sesión.
Sin embargo, dado que no hay un DROP TABLE al final del procedimiento almacenado, cuando el procedimiento almacenado se completa, deja la tabla creada para que pueda ser leída fuera del procedimiento almacenado.
En el pool de SQL dedicado, a diferencia de otras bases de datos de SQL Server, es posible usar la tabla temporal fuera del procedimiento que la creó. Las tablas temporales del grupo de SQL dedicado se pueden usar en cualquier lugar dentro de la sesión. Esta característica puede dar lugar a código más modular y administrable, como en el ejemplo siguiente:
EXEC [dbo].[prc_sqldw_update_stats] @update_type = 1, @sample_pct = NULL;
DECLARE @i INT = 1
, @t INT = (SELECT COUNT(*) FROM #stats_ddl)
, @s NVARCHAR(4000) = N''
WHILE @i <= @t
BEGIN
SET @s=(SELECT update_stats_ddl FROM #stats_ddl WHERE seq_nmbr = @i);
PRINT @s
EXEC sp_executesql @s
SET @i+=1;
END
DROP TABLE #stats_ddl;
Limitaciones de tabla temporal
El grupo de SQL dedicado impone un par de limitaciones al implementar tablas temporales. Actualmente, solo se admiten tablas temporales con ámbito de sesión. No se admiten tablas temporales globales.
Además, las vistas no se pueden crear en tablas temporales. Las tablas temporales solo se pueden crear con distribución hash o round robin. No se admite la distribución de tablas temporales replicadas.
Pasos siguientes
Para más información sobre el desarrollo de tablas, consulte el artículo Diseño de tablas mediante un grupo de SQL dedicado .