Tabelas temporárias no pool de SQL do Synapse
Este artigo contém as diretrizes essenciais de como usar as tabelas temporárias e destaca os princípios das tabelas temporárias no nível da sessão no SQL do Synapse.
O pool de SQL dedicado e os recursos do pool de SQL sem servidor podem utilizar tabelas temporárias. O pool SQL sem servidor tem limitações que são discutidas no final deste artigo.
Tabelas temporárias
As tabelas temporárias são úteis durante o processamento de dados - especialmente durante a transformação onde os resultados intermediários são transitórios. Com o SQL do Synapse, existem tabelas temporárias no nível da sessão. Elas são visíveis apenas para a sessão em que foram criadas. Assim, eles são descartados automaticamente quando essa sessão termina.
Tabelas temporárias no pool de SQL dedicado
No recurso de pool de SQL dedicado, as tabelas temporárias oferecem um benefício de desempenho, pois seus resultados são gravados no local, em vez do armazenamento remoto.
Criar uma tabela temporária
As tabelas temporárias são criadas simplesmente prefixando o nome da tabela com um #
. Por exemplo:
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
)
As tabelas temporárias também podem ser criadas usando CTAS
com a mesma abordagem:
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]
)
;
Observação
CTAS
é um comando potente com a vantagem extra de ser muito eficiente em seu uso do espaço de log das transações.
Soltar tabelas temporárias
Quando uma nova sessão é criada, não deve haver nenhuma tabela temporária. Contudo, se você estiver chamando o mesmo procedimento armazenado que cria um temporário com o mesmo nome, para garantir que suas instruções CREATE TABLE
sejam bem-sucedidas, use uma simples verificação de existência com DROP
:
IF OBJECT_ID('tempdb..#stats_ddl') IS NOT NULL
BEGIN
DROP TABLE #stats_ddl
END
Para a consistência da codificação, é recomendável usar esse padrão para as tabelas e as tabelas temporárias. Também é uma boa prática usar DROP TABLE
para remover as tabelas temporárias quando você tiver terminado o trabalho com elas.
No desenvolvimento de procedimento armazenado, é comum ver os comandos de remoção agrupados no fim de um procedimento para garantir que esses objetos sejam limpos.
DROP TABLE #stats_ddl
Modularizar código
As tabelas temporárias podem ser usadas em qualquer lugar em uma sessão de usuário. Esse recurso pode ser explorado para ajudá-lo a modularizar o código do aplicativo. Para demonstrar, o seguinte procedimento armazenado gera DDL para atualizar todas as estatísticas no banco de dados pelo nome da estatística:
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
Neste estágio, a única ação que ocorreu é a criação de um procedimento armazenado que simplesmente gera a tabela temporária, #stats_ddl. O procedimento armazenado remove #stats_ddl se ele já existir. Essa remoção garante que ele não falhará caso seja executado mais de uma vez em uma sessão.
Como não há nenhum DROP TABLE
no final do procedimento armazenado, quando o procedimento armazenado for concluído, a tabela criada é mantida e pode ser lida de fora do procedimento armazenado.
Ao contrário dos outros bancos de dados do SQL Server, o SQL do Synapse permite usar a tabela temporária fora do procedimento que a criou. As tabelas temporárias criadas por meio do pool de SQL dedicado podem ser usadas em qualquer lugar dentro da sessão. Como resultado, você terá um código mais modular e gerenciável, como demonstrado no exemplo a seguir:
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;
Limitações da tabela temporária
O pool SQL dedicado tem algumas limitações de implementação para tabelas temporárias:
- Somente a sessão com o escopo das tabelas temporárias tem suporte. Não há suporte para as Tabelas Temporárias Globais.
- As exibições não podem ser criadas em tabelas temporárias.
- As tabelas temporárias só podem ser criadas com a distribuição de hash ou round robin. Não há suporte para a distribuição de tabela temporária replicada.
As tabelas temporárias no pool de SQL sem servidor
As tabelas temporárias no pool de SQL sem servidor têm suporte, mas o uso delas é limitado. Elas não podem ser usadas em consultas que são arquivos de destino.
Por exemplo, não é possível ingressar em uma tabela temporária com dados de arquivos no armazenamento. O número de tabelas temporárias é limitado a 100 e seu tamanho total é limitado a 100 MB.
Próximas etapas
Para saber mais sobre como elaborar tabelas, confira o artigo Criação de tabelas usando os recursos de SQL do Synapse.