2017-03-30 22 views
0

私は400kk行のBIGテーブルを持っています。SQL Serverでパーティションをロックするテーブルをマージする

私はこのテーブルを分割したいのですが、2つの古いパーティション関数をマージするときに問題があります。

私はこのテーブルを持っている:

CREATE TABLE [dbo].[PartitionDemo](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [myDate] [date] NOT NULL, 
    [variable] [varchar](100) NULL, 
CONSTRAINT [pk_PartitionDemo] PRIMARY KEY CLUSTERED 
(
    [myDate] ASC, 
    [Id] ASC 
)ON [PartitionDemo_PS](mydate) 
) 

CREATE PARTITION SCHEME [PartitionDemo_PS] AS PARTITION [PartitionDemo_PF] TO ([PartitionDemo_FG_Prev], [PartitionDemo_FG_Historical], [PartitionDemo_FG_201609], [PartitionDemo_FG_201610], [PartitionDemo_FG_201611], [PartitionDemo_FG_201612], [PartitionDemo_FG_201701], [PartitionDemo_FG_201702], [PartitionDemo_FG_201703], [PartitionDemo_FG_201704]) 
GO 

CREATE PARTITION FUNCTION [PartitionDemo_PF](date) AS RANGE RIGHT FOR VALUES (N'2015-03-01T00:00:00.000', N'2016-09-01T00:00:00.000', N'2016-10-01T00:00:00.000', N'2016-11-01T00:00:00.000', N'2016-12-01T00:00:00.000', N'2017-01-01T00:00:00.000', N'2017-02-01T00:00:00.000', N'2017-03-01T00:00:00.000', N'2017-04-01T00:00:00.000') 
GO 

これは400kk行と私のテーブルです。私は、パーティションをマージするために何

は次のとおりです。

CREATE TABLE [staging].[PartitionDemo](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [myDate] [date] NOT NULL, 
    [variable] [varchar](100) NULL, 
CONSTRAINT [pk_PartitionDemo] PRIMARY KEY CLUSTERED 
(
    [myDate] ASC, 
    [Id] ASC 
)ON [PartitionDemo_PS](mydate) 
) 
GO 


ALTER TABLE PartitionDemo 
SWITCH PARTITION 2 TO [staging].[PartitionDemo] PARTITION 2 


ALTER TABLE PartitionDemo 
SWITCH PARTITION 3 TO [staging].[PartitionDemo] PARTITION 3 


ALTER PARTITION FUNCTION [PartitionDemo_PF]() 
    MERGE RANGE ('2016-03-01'); 

問題がマージしながら、両方のテーブルをロックしていることです。

この問題の回避策を教えてください。

+0

マージ後にデータを元のテーブルに戻す予定はありますか? –

+0

はい、私はデータを元に戻すでしょう、私はちょうどproblemaが前にあるので、ここでスクリプトを書いていません。 –

+0

私はコメントのために余りにも長い質問があります。 http://chat.stackoverflow.com/rooms/139493/merge-partition-locking-table-in-sql-serverでチャットに参加してください。 –

答えて

0

このファンクションとスキームを使用して最初の境界線を削除すると、2015-03-01より前のすべてのデータがファイルグループの代わりにPartitionDemo_FG_Prevファイルグループに移動されます。最初のパーティションが常に空であることを確認するには、パーティション境界をNULLにすることをお勧めします。これにより、この未使用のファイルグループからファイルを削除し、今後もパーティションのメンテナンスを容易にすることができます。このプラクティスの詳細については、http://www.dbdelta.com/table-partitioning-best-practices/を参照してください。

SWITCHMERGE、およびSPLITの操作中に簡単なスキーマ変更ロックが取得されますが、データの移動が不要なため、メタデータ操作が高速になるはずです。物理的なデータの移動はステージングテーブルCREATE INDEX...DROP_EXISTING-ONによって行われます。これにより、インデックスを再構築するソートが回避されます。このスクリプトは、SWITCHMERGE、およびSPLIT操作中に排他的なテーブルロックを取得して、他のアクティビティとのデッドロックを回避します。

--create staging table exactly like original table 
CREATE TABLE [staging].[PartitionDemo](
    [Id] [int] IDENTITY(1,1) NOT NULL, 
    [myDate] [date] NOT NULL, 
    [variable] [varchar](100) NULL, 
CONSTRAINT [pk_PartitionDemo] PRIMARY KEY CLUSTERED 
    (
     [myDate] ASC, 
     [Id] ASC 
    ) ON [PartitionDemo_PS](mydate) 
); 

--create temporary partition function and scheme with desired end state 
CREATE PARTITION FUNCTION [StagingPartitionDemo_PF](date) AS RANGE RIGHT FOR VALUES (
     CAST(NULL AS datetime)  --NULL boundary ensures first parttion is always empty 
    , N'2016-09-01T00:00:00.000' --upper boundary of historical data fg (less than this date) 
    , N'2016-10-01T00:00:00.000' 
    , N'2016-11-01T00:00:00.000' 
    , N'2016-12-01T00:00:00.000' 
    , N'2017-01-01T00:00:00.000' 
    , N'2017-02-01T00:00:00.000' 
    , N'2017-03-01T00:00:00.000' 
    , N'2017-04-01T00:00:00.000' 
    ); 
CREATE PARTITION SCHEME [StagingPartitionDemo_PS] AS PARTITION [StagingPartitionDemo_PF] TO (
     [PartitionDemo_FG_Prev] 
    , [PartitionDemo_FG_Historical] 
    , [PartitionDemo_FG_201609] 
    , [PartitionDemo_FG_201610] 
    , [PartitionDemo_FG_201611] 
    , [PartitionDemo_FG_201612] 
    , [PartitionDemo_FG_201701] 
    , [PartitionDemo_FG_201702] 
    , [PartitionDemo_FG_201703] 
    , [PartitionDemo_FG_201704] 
    ); 
GO 

SET XACT_ABORT ON; 
BEGIN TRAN; 

--acquire exclusive table lock to prevent deadlocking with concurrent activity 
SELECT TOP(0) myDate FROM dboPartitionDemo WITH(TABLOCKX); 

--switch first partition into staging (in case data exists before 2015-03-01) 
ALTER TABLE dbo.PartitionDemo 
    SWITCH PARTITION $PARTITION.PartitionDemo_PF(CAST(NULL AS datetime)) 
    TO [staging].[PartitionDemo] PARTITION $PARTITION.PartitionDemo_PF(CAST(NULL AS datetime)); 

--switch second partition into staging (on or after 2015-03-01 and before 2016-09-01) 
ALTER TABLE dbo.PartitionDemo 
    SWITCH PARTITION $PARTITION.PartitionDemo_PF('2015-03-01T00:00:00.000') 
    TO [staging].[PartitionDemo] PARTITION $PARTITION.PartitionDemo_PF('2015-03-01T00:00:00.000'); 

--switch third partition into staging (on or after 2016-09-01 and before 2016-10-01) 
ALTER TABLE dbo.PartitionDemo 
    SWITCH PARTITION $PARTITION.PartitionDemo_PF('2016-09-01T00:00:00.000') 
    TO [staging].[PartitionDemo] PARTITION $PARTITION.PartitionDemo_PF('2016-09-01T00:00:00.000'); 

COMMIT; 
GO 

--rebuild staging table on temporary partition scheme 
CREATE UNIQUE CLUSTERED INDEX pk_PartitionDemo ON staging.PartitionDemo(
     [myDate] ASC, 
     [Id] ASC 
    ) 
WITH(DROP_EXISTING=ON) 
ON [StagingPartitionDemo_PS](mydate); 
GO 

SET XACT_ABORT ON; 
BEGIN TRAN; 

--acquire exclusive table lock to prevent deadlocking with concurrent activity 
SELECT TOP(0) myDate FROM dboPartitionDemo WITH(TABLOCKX); 

--modify original partition scheme to match temporary one 
ALTER PARTITION SCHEME PartitionDemo_PS 
    NEXT USED PartitionDemo_FG_Historical; 
ALTER PARTITION FUNCTION PartitionDemo_PF() 
    SPLIT RANGE(CAST(NULL AS datetime)); 
ALTER PARTITION FUNCTION PartitionDemo_PF() 
    MERGE RANGE('2015-03-01T00:00:00.000'); 

--switch historical data partition partition back to main table 
ALTER TABLE staging.PartitionDemo 
    SWITCH PARTITION $PARTITION.PartitionDemo_PF(NULL) 
    TO dbo.[PartitionDemo] PARTITION $PARTITION.PartitionDemo_PF(CAST(NULL AS datetime)); 

--switch 2016-09-01 partition back to main table 
ALTER TABLE staging.PartitionDemo 
    SWITCH PARTITION $PARTITION.PartitionDemo_PF('2016-09-01T00:00:00.000') 
    TO dbo.[PartitionDemo] PARTITION $PARTITION.PartitionDemo_PF('2016-09-01T00:00:00.000'); 

COMMIT; 
GO 
+0

私の最初と最後の境界は常にNULLになります=)、私はそれを今日試してみます、ありがとうLOT。 –

関連する問題