SQL Server 2016 で追加された Temporal テーブルですが、Features Supported by the Editions of SQL Server 2016 に記載されているとおり、すべてのエディションで使用することができます。
ただし、履歴側のデータの保有期間を定めたい場合は、システム バージョン管理されたテンポラル テーブルの履歴データの保有期間管理 に書かれているような履歴テーブルのデータ削除を実装する必要がありますので、注意点を軽くまとめてみたいと思います。
現状、保存期間を定める方法はないため、基本的にはデータ削除をする仕組みを考える必要があります。
履歴テーブルの削除ですが、単純な DELETE 文では削除することができません。
これは、Temporal Table として指定している履歴テーブルについては DELETE が実行できないためです。
そのため、DELETE 文で削除を実施したい場合には、一度 Temporal を無効にしてから削除をこなう必要があります。
BEGIN TRAN EXEC ('ALTER TABLE [dbo].[TemporalTable] SET (SYSTEM_VERSIONING = OFF)') EXEC ('DELETE FROM [dbo].[TemporalTableHistory] WHERE SysEndTime <= DATEADD(dd, 2, GETDATE())') EXEC ('ALTER TABLE [dbo].[TemporalTable] SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.TemporalTableHistory, DATA_CONSISTENCY_CHECK = OFF ))') COMMIT TRAN [/sourcecode] </pre> </div> <p> </p> <p>このようなクエリを実行することで、削除中のデータの変更を防止したうえで、データを削除することができます。 <br />ただし、履歴に大量のデータが格納されているような状態ですとこのような削除を行うと、処理に時間がかかってしまい、オンラインに影響が出る可能性があります。</p> <p>そのため、瞬時にデータの削除を実施したい場合には、Enterprise Edition で使用することができるパーティショニングと組み合わせる必要があります。</p> <p>以下のようなクエリで、履歴側のテーブルをパーティショニングし、パーティショニングしたテーブルをスイッチするためのアーカイブテーブルを作成します。</p> <div id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:42fc5b66-2c25-4f4b-8028-09c4f5e3ff5e" class="wlWriterEditableSmartContent" style="float: none; padding-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px"><pre style=white-space:normal> [sourcecode language='sql' ] IF DB_ID('DemoDB') IS NULL CREATE DATABASE DemoDB GO USE DemoDB GO -- テスト用テーブルの作成 IF OBJECT_ID('TemporalTable_Partition') IS NOT NULL BEGIN ALTER TABLE TemporalTable_Partition SET (SYSTEM_VERSIONING = OFF) DROP TABLE TemporalTable_Partition END GO -- テスト用テーブルの作成 IF OBJECT_ID('TemporalTableHistory_Partition') IS NOT NULL DROP TABLE TemporalTableHistory_Partition GO IF OBJECT_ID('TemporalTableHistory_Archive') IS NOT NULL DROP TABLE TemporalTableHistory_Archive GO DROP PARTITION SCHEME PS_TemporalTableHistory_Partition DROP PARTITION FUNCTION PF_TemporalTableHistory_Partition GO -- 履歴用テーブルの作成(SysEndTime でパーティショニング) CREATE TABLE TemporalTableHistory_Partition( Col1 int NOT NULL, Col2 uniqueidentifier, Col3 uniqueidentifier, Col4 nvarchar(10), SysStartTime datetime2 NOT NULL, SysEndTime datetime2 NOT NULL ) GO CREATE PARTITION FUNCTION [PF_TemporalTableHistory_Partition](datetime2) AS RANGE RIGHT FOR VALUES (N'2016-01-01',N'2017-01-01',N'2018-01-01') GO CREATE PARTITION SCHEME [PS_TemporalTableHistory_Partition] AS PARTITION [PF_TemporalTableHistory_Partition] ALL TO ([PRIMARY]) GO -- ベーステーブルの作成 CREATE TABLE TemporalTable_Partition( Col1 int IDENTITY PRIMARY KEY CLUSTERED, Col2 uniqueidentifier, Col3 uniqueidentifier, Col4 nvarchar(10), SysStartTime datetime2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL , SysEndTime datetime2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime) ) WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.TemporalTableHistory_Partition)) GO -- 履歴テーブルにインデックスを設定 (履歴テーブルに設定後にインデックスを作成しないと消えてしまっていたので注意) CREATE CLUSTERED INDEX [CIX_TemporalTableHistory] ON [dbo].[TemporalTableHistory_Partition] ( [SysEndTime] ASC, [SysStartTime] ASC ) WITH (DATA_COMPRESSION = PAGE) ON [PS_TemporalTableHistory_Partition] ([SysEndTime]) GO -- 履歴テーブルアーカイブ用 CREATE TABLE TemporalTableHistory_Archive( Col1 int NOT NULL, Col2 uniqueidentifier, Col3 uniqueidentifier, Col4 nvarchar(10), SysStartTime datetime2 NOT NULL, SysEndTime datetime2 NOT NULL ) GO CREATE CLUSTERED INDEX [CIX_TemporalTableArchive] ON [dbo].[TemporalTableHistory_Archive] ( [SysEndTime] ASC, [SysStartTime] ASC ) WITH (DATA_COMPRESSION = PAGE) GO SELECT OBJECT_NAME(sp.object_id) , si.name , sp.partition_number , sp.rows , sp.data_compression_desc , si.type_desc FROM sys.partitions sp LEFT JOIN sys.indexes as si ON si.object_id = sp.object_id AND si.index_id = sp.index_id WHERE sp.object_id IN (OBJECT_ID(N'dbo.TemporalTableHistory_Partition')) GO SELECT * FROM sys.partition_range_values prv INNER JOIN sys.partition_functions pf ON prv.function_id = pf.function_id
この状態で以下のようなクエリを流すことで、データの削除をパーティショニングのスイッチにより実施することができます。
USE DemoDB GO -- テストデータの確認 INSERT INTO TemporalTable_Partition (Col2, Col3, Col4) VALUES(NEWID(), NEWID(), N'AAAAAA'), (NEWID(), NEWID(), N'AAAAAA'), (NEWID(), NEWID(), N'AAAAAA'), (NEWID(), NEWID(), N'AAAAAA') WAITFOR DELAY '00:00:01' BEGIN TRAN INSERT INTO TemporalTable_Partition (Col2, Col3, Col4) VALUES (NEWID(), NEWID(), N'AAAAAA') INSERT INTO TemporalTable_Partition (Col2, Col3, Col4) VALUES (NEWID(), NEWID(), N'AAAAAA') COMMIT TRAN WAITFOR DELAY '00:00:01' BEGIN TRAN INSERT INTO TemporalTable_Partition (Col2, Col3, Col4) VALUES (NEWID(), NEWID(), N'AAAAAA') INSERT INTO TemporalTable_Partition (Col2, Col3, Col4) VALUES (NEWID(), NEWID(), N'AAAAAA') COMMIT TRAN WAITFOR DELAY '00:00:01' GO UPDATE TemporalTable_Partition SET Col2 = NEWID() GO SELECT *,$PARTITION.PF_TemporalTableHistory_Partition(SysEndTime) FROM [TemporalTableHistory_Partition] SELECT * FROM [TemporalTableHistory_Archive] GO -- パーティションのスイッチ ALTER TABLE [dbo].[TemporalTableHistory_Partition] SWITCH PARTITION 2 TO [dbo].[TemporalTableHistory_Archive] WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 0 MINUTES, ABORT_AFTER_WAIT = NONE)) GO ALTER PARTITION FUNCTION [PF_TemporalTableHistory_Partition]() MERGE RANGE(N'2016-01-01') GO SELECT *,$PARTITION.PF_TemporalTableHistory_Partition(SysEndTime) FROM [TemporalTableHistory_Partition] SELECT * FROM [TemporalTableHistory_Archive] GO TRUNCATE TABLE [TemporalTableHistory_Archive] GO SELECT * FROM [TemporalTableHistory_Archive]
SQL Database であれば、パフォーマンスレベルに関係なく、パーティショニングが使用できたはずですので、この辺は柔軟に実施できるはずですが、オンプレミスの SQL Server を使用する場合には、履歴側のデータを保有期間と削除方法は、意識しておくと良いかと。