Synapse SQL の一時テーブル
この記事では、Synapse SQL 内のセッション レベルの一時テーブルの原則を中心に、一時テーブルの基本的な利用方法について説明します。
専用 SQL プールとサーバーレス SQL プールの両方のリソースで、一時テーブルを利用できます。 サーバーレス SQL プールにはいくつかの制限事項があり、それについては、この記事の最後で説明しています。
一時テーブル
特に、中間結果が一時的なものである変換中にデータを処理する場合に、一時テーブルが役立ちます。 Synapse SQL では、一時テーブルはセッション レベルで存在します。 一時テーブルは、それが作成されたセッションにのみ表示されます。 そのため、そのセッションが終了すると自動的に削除されます。
専用 SQL プール内の一時テーブル
専用 SQL プール リソースでは、一時テーブルの結果がリモート ストレージではなくローカル ストレージに書き込まれるため、パフォーマンス上の利点があります。
一時テーブルを作成する
一時テーブルは、テーブル名にプレフィックス #
を付けることで作成できます。 次に例を示します。
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
)
一時テーブルは、次のようにまったく同じ手法で CTAS
を利用して作成することもできます。
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]
)
;
Note
CTAS
は強力なコマンドであり、トランザクション ログ領域を効率的に利用するという長所があります。
一時テーブルを削除する
新しいセッションが作成されたとき、一時テーブルは存在しません。 ただし、同じ名前で一時テーブルを作成する同じストアド プロシージャを呼び出す場合、CREATE TABLE
ステートメントを正常に実行するために、DROP
による簡単な既存チェックを使用します。
IF OBJECT_ID('tempdb..#stats_ddl') IS NOT NULL
BEGIN
DROP TABLE #stats_ddl
END
コードの一貫性のために、テーブルと一時テーブルの両方にこのパターンを利用することが推奨されます。 また、一時テーブルの利用を終えたら、DROP TABLE
を使用してそれを削除することもお勧めします。
ストアド プロシージャの開発では、一般的に、オブジェクトが消去されるように、プロシージャの終わりに削除コマンドがバンドルされています。
DROP TABLE #stats_ddl
コードをモジュール化する
一時テーブルはユーザー セッション内のどこでも使用できます。 この機能を利用して、アプリケーション コードをモジュール化することができます。 試してみるには、次のストアド プロシージャで、データベース内のすべての統計を統計名で更新する DDL を生成します。
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
この段階で、発生した唯一のアクションは、#stats_ddl 一時テーブルを生成するストアド プロシージャの作成です。 #stats_ddl が既に存在する場合は、このストアド プロシージャによって削除されます。 この削除により、一時テーブルがセッション内で複数回実行された場合に失敗することがなくなります。
ストアド プロシージャの最後に DROP TABLE
がないため、ストアド プロシージャが完了したときに、作成されたテーブルはそのまま残り、ストアド プロシージャの外部で読み取ることができます。
他の SQL Server データベースとは対照的に、Synapse SQL では、一時テーブルを作成したプロシージャの外部でその一時テーブルを使用できます。 専用 SQL プールを使用して作成された一時テーブルは、セッション内のどこでも使用できます。 その結果、以下のサンプルに示すように、コードのモジュール性が高まり、コードを管理しやすくなります。
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;
一時テーブルの制限事項
専用 SQL プールには、一時テーブルの実装上の制限事項がいくつかあります。
- セッションを範囲とした一時テーブルのみがサポートされています。 グローバル一時テーブルはサポートされていません。
- 一時テーブルでビューを作成することはできません。
- 一時テーブルは、ハッシュまたはラウンド ロビン ディストリビューションでのみ作成できます。 レプリケートされた一時テーブルのディストリビューションはサポートされていません。
サーバーレス SQL プール内の一時テーブル
サーバーレス SQL プール内の一時テーブルはサポートされていますが、その使用法は制限されています。 一時テーブルは、ファイルを対象とするクエリでは使用できません。
たとえば、ストレージ内のファイルからのデータと一時テーブルを結合することはできません。 一時テーブルの数は 100 個に制限されており、合計サイズは 100 MB に制限されています。
次のステップ
テーブルの開発について詳しくは、Synapse SQL リソースを使用したテーブルの設計に関する記事をご覧ください。