スライディング ウィンドウ パーティションのメンテナンスは通常、スケジュールされたスクリプトまたはストアド プロシージャ (SQL Server エージェント ジョブまたはその他のスケジュール システム) を使用して行われます。 SPLIT
中のコストのかかるデータ移動を避けるために、メンテナンスを計画する必要があります。 および MERGE
通常の DML 操作の約 4 倍のログが必要になるためです。このために、 MERGE
の前に、境界値を含むパーティションが空であることを確認してください SPLIT
の場合、指定された境界を超える行はありません .メンテナンスが計画どおりに実行されない場合に備えて、データの移動を回避するためのバッファーとして、いくつかの追加の将来のパーティションを作成することをお勧めします。
以下は、毎日のスライディング ウィンドウ メンテナンス スクリプトの例です。これは、SQL Server 2005 とパーティション レベルの TRUNCATE
を使用しているため、同様にパーティション分割されたステージング テーブルをパージに使用します。 は SQL Server 2016 で導入されました。SQL Server 2005 はサポートされていないことに注意してください。
あなたのコメントから、パーティションごとに個別のファイルグループ/ファイルがパーティションを削除するのに役立つと思われることがわかりますが、そうではありません。この例では、すべてのパーティションに対して 1 つのファイル グループを使用しています。
--example setup
CREATE PARTITION FUNCTION PF_Date (datetime) AS
RANGE RIGHT FOR VALUES();
CREATE PARTITION SCHEME PS_LogTable AS
PARTITION PF_Date ALL TO ([PRIMARY]);
DECLARE @PartitionBoundaryDate datetime = DATEADD(day, -31, DATEADD(day, DATEDIFF(day, '', GETDATE()), ''));
WHILE @PartitionBoundaryDate < DATEADD(day, 1, GETDATE())
BEGIN
ALTER PARTITION SCHEME PS_LogTable NEXT USED [PRIMARY];
ALTER PARTITION FUNCTION PF_Date() SPLIT RANGE(@PartitionBoundaryDate);
SET @PartitionBoundaryDate = DATEADD(day, 1, @PartitionBoundaryDate)
END;
CREATE TABLE dbo.LogTable(DateColumn datetime INDEX cdx CLUSTERED) ON PS_LogTable(DateColumn);
CREATE TABLE dbo.LogTable_Staging(DateColumn datetime INDEX cdx CLUSTERED) ON PS_LogTable(DateColumn);
GO
--example partition maintenance scheduled nightly after midnight
BEGIN TRY
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @RetentionDays int = 31;
DECLARE @FutureDays int = 7;
DECLARE @OldestRetainedDate datetime = DATEADD(day, [email protected], DATEADD(day, DATEDIFF(day, '', GETDATE()), ''));
DECLARE @LatestRetainedDate datetime = DATEADD(day, DATEDIFF(day, '', GETDATE()), '');
DECLARE @LatestFutureBoundaryDate datetime = DATEADD(day, @FutureDays, @LatestRetainedDate);
DECLARE @PartitionBoundaryDate datetime;
DECLARE @Message nvarchar(2048);
--make sure staging table is empty
TRUNCATE TABLE dbo.LogTable_Staging;
BEGIN TRAN;
--aquire exclusive table lock to avoid deadlocking during maintenance
SELECT TOP(0) @PartitionBoundaryDate = DateColumn FROM dbo.LogTable WITH(TABLOCKX);
--purge partition 1 in case data older than the first boundary was inserted
SET @Message = 'Purging partition 1';
PRINT @Message;
ALTER TABLE dbo.LogTable SWITCH
PARTITION 1 TO
dbo.LogTable_Staging PARTITION 1;
TRUNCATE TABLE dbo.LogTable_Staging;
--purge and remove expired partitions
DECLARE @PartitionBoundaries TABLE(PartitionBoundaryDate datetime NOT NULL PRIMARY KEY);
INSERT INTO @PartitionBoundaries(PartitionBoundaryDate)
SELECT CAST(prv.value AS datetime)
FROM sys.partition_functions AS pf
JOIN sys.partition_range_values AS prv ON prv.function_id = pf.function_id
WHERE
pf.name = N'PF_Date'
AND CAST(prv.value AS datetime) < @OldestRetainedDate;
DECLARE ExpiredPartitionBoundaries CURSOR LOCAL FAST_FORWARD FOR
SELECT PartitionBoundaryDate
FROM @PartitionBoundaries;
OPEN ExpiredPartitionBoundaries;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM ExpiredPartitionBoundaries INTO @PartitionBoundaryDate;
IF @@FETCH_STATUS = -1 BREAK;
SET @Message = 'Purging data for ' + CONVERT(char(10), @PartitionBoundaryDate, 120);
PRINT @Message;
ALTER TABLE dbo.LogTable SWITCH
PARTITION $PARTITION.PF_Date(@PartitionBoundaryDate) TO
dbo.LogTable_Staging PARTITION $PARTITION.PF_Date(@PartitionBoundaryDate);
TRUNCATE TABLE dbo.LogTable_Staging;
ALTER PARTITION FUNCTION PF_Date() MERGE RANGE(@PartitionBoundaryDate);
END;
CLOSE ExpiredPartitionBoundaries;
DEALLOCATE ExpiredPartitionBoundaries;
--create partitions for future days
SET @PartitionBoundaryDate = DATEADD(day, 1, @LatestRetainedDate);
WHILE @PartitionBoundaryDate < = @LatestFutureBoundaryDate
BEGIN
IF NOT EXISTS(SELECT 1
FROM sys.partition_functions AS pf
JOIN sys.partition_range_values AS prv ON prv.function_id = pf.function_id
WHERE
pf.name = N'PF_Date'
AND CAST(prv.value AS datetime) = @PartitionBoundaryDate
)
BEGIN
SET @Message = 'Creating partition for ' + CONVERT(char(10), @PartitionBoundaryDate, 120);
PRINT @Message;
ALTER PARTITION SCHEME PS_LogTable NEXT USED [PRIMARY];
ALTER PARTITION FUNCTION PF_Date() SPLIT RANGE(@PartitionBoundaryDate);
END;
SET @PartitionBoundaryDate = DATEADD(day, 1, @PartitionBoundaryDate);
END;
COMMIT;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK;
--better to use THROW in SQL 2012 and later
DECLARE
@ErrorNumber int
,@ErrorMessage nvarchar(2048)
,@ErrorSeverity int
,@ErrorState int
,@ErrorLine int;
SELECT
@ErrorNumber =ERROR_NUMBER()
,@ErrorMessage =ERROR_MESSAGE()
,@ErrorSeverity = ERROR_SEVERITY()
,@ErrorState =ERROR_STATE()
,@ErrorLine =ERROR_LINE();
RAISERROR('Error %d caught at line %d: %s'
,@ErrorSeverity
,@ErrorState
,@ErrorNumber
,@ErrorLine
,@ErrorMessage);
END CATCH;
GO