SQL Server 2014 Enterprise Editionと約6 TB=のサイズのデータベースがあります。
サーバーがAzureにあり、9のプレミアムディスクがあるため、インフラの素早いバックグラウンドを提供するためだけにTB for datafiles。
識別子(MonthlyDate integer Eg 01012016、... 31122016)によって既にパーティション分割されているいくつかの大きなテーブルを用意します。 2014年から2016年までの月次パーティションがあります(01012014、01022014 ...... 31122016まで)。
今、私たちは2017年と2018年のパーティションを月単位で作成しようとしています。
パーティションウィザードを使用しようとしましたが、必要なオプションが見つかりませんでした。私が知る限り、私は次のようなものを実行する必要があります:
Alter partition Scheme [PartPScheme_BIGTAB] Next Used [PartFileGrp_201701]
Alter partition Function [PartPFN_BIGTAB] () split range(20170131)
上記のスクリプトを複数回実行しようとしましたが、7時間以上かかって、データの1 GBのみがパーティションの上に移動されたので、最後にスクリプトをロールバックする必要があります。
この種のベストプラクティスについて、正しい方向に向けてくれる人を探しています。これにどのように取り組むか本当にわかりません。
問題は何でしょうか?
現在のパーティション関数は次のとおりです。
CREATE PARTITION FUNCTION [PartPFN_BIGTAB](int) AS RANGE LEFT FOR VALUES (
20141031
, 20141131
, 20141231
, 20150131
, 20150231
, 20150331
, 20150431
, 20150531
, 20150631
, 20150731
, 20150831
, 20150931
, 20151031
, 20151131
, 20151231
, 20160131
, 20160231
, 20160331
, 20160431
, 20160531
, 20160631
, 20160731
, 20160831
, 20160931
, 20161031
, 20161131
, 20161231
);
あなたの意図がこのデータを年/月ごとに分割することである場合、私はあなたの現在の分割列(整数であり、「真の」日付データ型ではなく、整数としてもyyyymmdd形式でさえない)はすべてジョブにとって間違っていると思います。また、表にIS真の日付データ型のMonthlyDateである別の列がないと仮定します。
私の意見では(さらにディスク容量がある場合)、次のことを行う必要があります。
DATE
データ型を使用する新しいパーティション関数を作成します。これはRANGE RIGHT
(説明については、この回答の下部にあるDan Guzmanのリンクを参照してください)。最小日付よりかなり下の範囲と、最大日付よりかなり上の範囲で作成してください。また、時間がたつにつれて、空のパーティションを、すでにデータが入力されているデータよりもはるかに先に分割していることを確認してください。パーティション化シナリオに参加するすべての一意のインデックスは、単に含まれている列ではなく、ベースインデックス定義の一部として定義されているパーティション化列を持つ必要があることに注意してください。
また、パーティション切り替え(「スライディングウィンドウ」でよく使用される)を有効にするには、テーブルのすべてのインデックスを揃える必要があります。 BOLはこれについて良い情報を持っています。 パーティション化インデックスの特別なガイドライン を探します。
最後に、Dan GuzmanのSQL Serverパーティショニングに関する excellent post を確認してください。
年が始まる前に、2017パーティションを作成しておく必要があります。これで、最後のパーティションには2016年12月1日から現在までのすべてのデータが含まれています。分割するときは、すべての行を物理的に新しいパーティションに移動する必要があります。
参照: https://docs.Microsoft.com/en-us/sql/t-sql/statements/alter-partition-function-transact-sql
パーティションの分割(新しいデータをロードする前)とパーティションのマージ(古いデータをアンロードした後)でデータの移動が発生しないように、常にパーティション範囲の両端に空のパーティションを保持します。移入されたパーティションを分割またはマージしないでください。これにより、ログ生成が4倍も多くなり、重大なロックが発生する可能性があるため、これは非常に非効率的です。
IOへの影響を最小限に抑えるために使用できるアプローチはいくつかあります。以下の記事に記載されている解決策は最高の解決策の1つです。また、Microsoftの最高のフィールドエンジニアチームによって書かれています。
おっと…空のSQLテーブルパーティションを残すのを忘れたのですが、最小限の分割でどうすれば分割できますかIO影響?
ケンドラリトルによるもう1つの良い読み物です。
編集:@ScottHodginのコメントに基づくと、パーティション列が整数データ型であり、日時型または日付型ではない場合、より大きな問題が発生する可能性があります。同時にこれを修正したいかもしれません。
コメントの追加情報に基づいて、現在のパーティション関数の境界値はYYYYMM31のようです。実際のパーティション列の値がYYYYMMDD形式であると想定すると、一時的なパーティション関数とスキームと共にステージングテーブルとSWITCH
を使用できるはずです。
以下は、このメソッドを使用したスクリプトの例です。空ではないパーティションの分割を避けるために、事前に計画するのが最善であるとScottとSqlWordWideに同意します。変更できないレガシースキーマがない限り、パーティション列は日付データ型である必要があります。これにより、有効な日付のみが存在し、より直感的なパーティション境界とメンテナンススクリプトが可能になります。
--create temporary partition function and scheme with desired boundaries and filegroup mapping
DECLARE
@StartMonth date = '20141001'
, @EndMonth date = '20181201'
, @Month date
, @SQL nvarchar(MAX);
CREATE PARTITION FUNCTION PartPFN_BIGTAB_Temp(int) AS RANGE LEFT FOR VALUES ();
CREATE PARTITION SCHEME PartPScheme_BIGTAB_Temp
AS PARTITION PartPFN_BIGTAB_Temp ALL TO ([DEFAULT]);
SET @Month = @StartMonth;
WHILE @Month <= @EndMonth
BEGIN
SET @SQL = REPLACE(
N'ALTER PARTITION SCHEME PartPScheme_BIGTAB_Temp NEXT USED PartFileGrp_$(YYYYMM);'
, N'$(YYYYMM)'
, LEFT(CONVERT(char(8), @Month, 112), 6)
);
PRINT @SQL;
EXEC sp_executesql @SQL;
ALTER PARTITION FUNCTION PartPFN_BIGTAB_Temp()
SPLIT RANGE(CAST(LEFT(CONVERT(char(8), @Month, 112), 6) + '31' AS int));
SET @Month = DATEADD(month, 1, @Month);
END;
GO
--create aligned temporary staging table with same schema and indexes on original partition scheme
CREATE TABLE dbo.YourPartitionedTable_Staging(
YYYYMMDDColumn int
, OtherColumn int
, CONSTRAINT PK_YourPartitionedTable_Staging
PRIMARY KEY (
OtherColumn
, YYYYMMDDColumn
) ON PartPScheme_BIGTAB(YYYYMMDDColumn)
) ON PartPScheme_BIGTAB(YYYYMMDDColumn);
--switch last partition ( first value > 20161231 ) into staging table
ALTER TABLE dbo.YourPartitionedTable SWITCH
PARTITION $PARTITION.PartPFN_BIGTAB(20161232)
TO dbo.YourPartitionedTable_Staging
PARTITION $PARTITION.PartPFN_BIGTAB(20161232);
--recreate each index on temporary scheme using CREATE...INDEX...DROP_EXISTING
CREATE UNIQUE CLUSTERED INDEX PK_YourPartitionedTable_Staging ON dbo.YourPartitionedTable_Staging
(
OtherColumn
, YYYYMMDDColumn
)
WITH (DROP_EXISTING=ON)
ON PartPScheme_BIGTAB_Temp(YYYYMMDDColumn);
GO
--create new boundaries in original partition function along with filegroups mappings
DECLARE
@StartMonth date = '20170101'
, @EndMonth date = '20181201'
, @Month date
, @SQL nvarchar(MAX);
SET @Month = @StartMonth;
WHILE @Month <= @EndMonth
BEGIN
SET @SQL = REPLACE(
N'ALTER PARTITION SCHEME PartPScheme_BIGTAB NEXT USED PartFileGrp_$(YYYYMM);'
, N'$(YYYYMM)'
, LEFT(CONVERT(char(8), @Month, 112), 6)
);
PRINT @SQL;
EXEC sp_executesql @SQL;
ALTER PARTITION FUNCTION PartPFN_BIGTAB()
SPLIT RANGE(CAST(LEFT(CONVERT(char(8), @Month, 112), 6) + '31' AS int));
SET @Month = DATEADD(month, 1, @Month);
END;
GO
--SWITCH data in new parttions bach into original table
DECLARE
@StartMonth date = '20171001'
, @EndMonth date = '20181201'
, @Month date;
SET @Month = @StartMonth;
WHILE @Month <= @EndMonth
BEGIN
ALTER TABLE dbo.YourPartitionedTable_Staging SWITCH
PARTITION $PARTITION.PartPFN_BIGTAB(CAST(LEFT(CONVERT(char(8), @Month, 112), 6) + '31' AS int))
TO dbo.YourPartitionedTable
PARTITION $PARTITION.PartPFN_BIGTAB(CAST(LEFT(CONVERT(char(8), @Month, 112), 6) + '31' AS int));
SET @Month = DATEADD(month, 1, @Month);
END;
GO
--generally a good practice to update stats after SWITCH, although may not be reqiired here because data did not change
UPDATE STATISTICS dbo.YourPartitionedTable;
GO
--remove temporary objects
DROP TABLE dbo.YourPartitionedTable_Staging
DROP PARTITION SCHEME PartPScheme_BIGTAB_Temp;
DROP PARTITION FUNCTION PartPFN_BIGTAB_Temp;
GO