web-dev-qa-db-ja.com

SQL Serverでのパーティション列の変更

1億行以上のパーティションテーブルを作成し、テーブルの作成時に誤ってdatetime列をパーティションキーとして指定しました。

パーティション列をdatetime列から別の列に変更する簡単な方法はありますか?私の場合、列InsertedDateCompleteDateがあり、2つ目の列ではなく最初の列を誤って使用しました。

3
Lóri Nóda

何億もの行があるテーブルのパーティション列を変更すると、テーブル内のすべての行、およびおそらく関連するインデックスが操作によって物理的に移動される必要があるため、少し面倒になる可能性があります。各パーティションを再構築するのに十分なストレージ容量があることを確認する必要があります。おそらく、テーブルを新しいファイルグループのセットに移動し、その後、古い未使用のファイルグループを削除します。

テーブルに主キーまたは一意のインデックスが定義されている場合、それらを削除して再作成し、新しいパーティション列をインデックスキーに含める必要があります。

テーブルに主キーがあり、その主キーが他のテーブルで参照されている場合、パーティションキーを変更するには、参照整合性を解除する必要があります。現在InsertedDate列を区分化キーとして使用していて、それをCompletedDate列を使用するように移動したいので、おそらく両方の日付データ型であるので、これが状況に影響を与えるとは思いません-知っておく価値があるだけです。

主キーを持つテーブルの場合、テーブルをあるパーティションキーから別のパーティションキーに移動する実際のタスクは、主キー制約を削除してから、新しいパーティションキーを主キーの一部としてテーブルを再構築することです。

24のパーティションに10,000,000行が分散された小さなテストベッドを組み立てて、これが実際に動作していることを確認します。

作業はtempdbで行うので、ある程度の拡張に十分なスペースがあることを確認してください。まず、パーティション関数、パーティション構成、そして最後にテーブル自体を作成します。

USE tempdb;
GO
IF OBJECT_ID(N'dbo.Tab', N'U') IS NOT NULL
BEGIN
    DROP TABLE dbo.Tab;
END
IF EXISTS (SELECT 1 FROM sys.partition_schemes ps WHERE ps.name = N'PartScheme')
BEGIN
    DROP PARTITION SCHEME PartScheme;
END
IF EXISTS (SELECT 1 FROM sys.partition_functions pf WHERE pf.name = N'PartFun')
BEGIN
    DROP PARTITION FUNCTION PartFun;
END

CREATE PARTITION FUNCTION PartFun (datetime)
AS RANGE LEFT
FOR VALUES (
      N'2012-01-01T00:00:00'
    , N'2012-04-01T00:00:00'
    , N'2012-07-01T00:00:00'
    , N'2012-10-01T00:00:00'
    , N'2013-01-01T00:00:00'
    , N'2013-04-01T00:00:00'
    , N'2013-07-01T00:00:00'
    , N'2013-10-01T00:00:00'
    , N'2014-01-01T00:00:00'
    , N'2014-04-01T00:00:00'
    , N'2014-07-01T00:00:00'
    , N'2014-10-01T00:00:00'
    , N'2015-01-01T00:00:00'
    , N'2015-04-01T00:00:00'
    , N'2015-07-01T00:00:00'
    , N'2015-10-01T00:00:00'
    , N'2016-01-01T00:00:00'
    , N'2016-04-01T00:00:00'
    , N'2016-07-01T00:00:00'
    , N'2016-10-01T00:00:00'
    , N'2017-01-01T00:00:00'
    , N'2017-04-01T00:00:00'
    , N'2017-07-01T00:00:00'
    , N'2017-10-01T00:00:00'
);

CREATE PARTITION SCHEME PartScheme
AS PARTITION PartFun
ALL TO ([PRIMARY]);

IF OBJECT_ID(N'dbo.Tab', N'U') IS NOT NULL
DROP TABLE dbo.Tab;
CREATE TABLE dbo.Tab
(
    TabID int NOT NULL
    , CreateDate datetime NOT NULL
    , UpdateDate datetime NOT NULL
    , Data1 varchar(100) NOT NULL
    , Data2 varchar(100) NOT NULL
    , Data3 varchar(100) NOT NULL
    , CONSTRAINT PK_Tab
        PRIMARY KEY CLUSTERED
        (CreateDate, TabID)
) ON [PartScheme](CreateDate);

これにより、テーブルは各パーティションにいくらか均等に分散した10,000,000行で埋められます。

;WITH Ten AS
(
    SELECT v.Num
    FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9))v(Num)
)
, TenMillion AS 
(
    SELECT Num = (t7.Num * POWER(10, 6))
        + (t6.Num * POWER(10, 5)) 
        + (t5.Num * POWER(10, 4)) 
        + (t4.Num * POWER(10, 3)) 
        + (t3.Num * POWER(10, 2)) 
        + (t2.Num * POWER(10, 1)) 
        + (t1.Num) 
    FROM Ten t1
        CROSS JOIN Ten t2
        CROSS JOIN Ten t3
        CROSS JOIN Ten t4
        CROSS JOIN Ten t5
        CROSS JOIN Ten t6
        CROSS JOIN Ten t7
)
INSERT INTO dbo.Tab (TabID, CreateDate, UpdateDate, Data1, Data2, Data3)
SELECT m.Num, DATEADD(DAY, m.Num % 1825, N'2012-01-01T00:00:00')
    , DATEADD(DAY, m.Num % 1825, N'2012-02-02T00:00:00')
    , CONVERT(varchar(100), CRYPT_GEN_RANDOM(100))
    , CONVERT(varchar(100), REPLICATE('A', 100))
    , CONVERT(varchar(100), REPLICATE('B', 100))
FROM TenMillion m;

テーブルの行の分布:

SELECT ObjectName = s.name + '.' + o.name
    , p.partition_number
    , p.rows
FROM sys.partitions p
    INNER JOIN sys.objects o ON o.object_id = p.object_id
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE s.name = 'dbo'
    AND o.name = 'Tab'
    AND p.index_id = 1
ORDER BY p.partition_number;
╔════════════╦══════════════════╦════════╗
║ObjectName║ partition_number║行║
╠════════════╬══════════════════╬════════ ╣
║dbo.Tab║1║5480║
║dbo.Tab║2║498680║
║dbo.Tab║3 498 498680║
║dbo .Tab║4║504160║
║dbo.Tab║5║504160║
║dbo.Tab║6║493200║
║dbo.Tab║7║498680║
║dbo.Tab║8║504160║
║dbo.Tab║9║504160║
║dbo.Tab║10║493200║
║dbo.Tab ║11║498592║
║dbo.Tab║12║504068║
║dbo.Tab║13║504068║
║dbo.Tab║14 493 493110║
║dbo.Tab║15║498589║
║dbo.Tab║16║504068║
║dbo.Tab║17║504068║
 ║dbo.Tab║18║498589║
║dbo.Tab║19║498589║
║dbo.Tab║20║504068║
║dbo.Tab║21║487631 ║
║dbo.Tab║22║0║
║dbo.Tab║23║0║
║dbo.Tab║24║0║
║dbo .Tab║25║0║
╚════════════╩══════════════════╩═════ ═══╝

これにより、元の主キーを削除した後、新しいパーティションキーでテーブルが再構築されます。ここでの効果は、テーブルをクラスター化インデックスからヒープに移動し、クラスター化インデックスに戻すことです。誤ってテーブルをヒープとして残さないように、トランザクションでこれを行っています。

BEGIN TRANSACTION;

BEGIN TRY
    ALTER TABLE dbo.Tab
    DROP CONSTRAINT PK_Tab
    WITH (MOVE TO PartScheme(UpdateDate));

    ALTER TABLE dbo.Tab
    ADD CONSTRAINT PK_Tab
    PRIMARY KEY CLUSTERED
    (UpdateDate, TabID)
    ON PartScheme(UpdateDate);

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION
END CATCH

sys.partitionsクエリを実行すると、一部の行が別のパーティションに移動されたため、行数が変更されたことがわかります。

SELECT ObjectName = s.name + '.' + o.name
    , p.partition_number
    , p.rows
FROM sys.partitions p
    INNER JOIN sys.objects o ON o.object_id = p.object_id
    INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE s.name = 'dbo'
    AND o.name = 'Tab'
    AND p.index_id = 1
ORDER BY p.partition_number;
╔════════════╦══════════════════╦════════╗
║ObjectName║ partition_number║行║
╠════════════╬══════════════════╬════════ ╣
║dbo.Tab║1║0║
║dbo.Tab║2║328800║
║dbo.Tab║3 498 498680║
║dbo .Tab║4║504160║
║dbo.Tab║5║504160║
║dbo.Tab║6║493200║
║dbo.Tab║7║498680║
║dbo.Tab║8║504160║
║dbo.Tab║9║504160║
║dbo.Tab║10║493200║
║dbo.Tab ║11║498624║
║dbo.Tab║12║504068║
║dbo.Tab║13║504068║
║dbo.Tab║14 493 493110║
║dbo.Tab║15║498589║
║dbo.Tab║16║504068║
║dbo.Tab║17║504068║
 ║dbo.Tab║18║498589║
║dbo.Tab║19║498589║
║dbo.Tab║20║504068║
║dbo.Tab║21║504068 ║
║dbo.Tab║22║158891║
║dbo.Tab║23║0║
║dbo.Tab║24║0║
║dbo .Tab║25║0║
╚════════════╩══════════════════╩═════ ═══╝

参考までに、RAMが制限されているワークステーションのパーティション分割キーと、同じディスク上のすべてのパーティションを変更すると、1,000万行で14分以上かかりました。非本番システムでこれを実践して、影響を確実に理解し、これにかかる時間を把握する必要があります。再構築の実行中はクライアントアクティビティが発生しないことを理解しているため、ダウンタイムを計画する必要があります。

4
Max Vernon