将分区表的分区移动到其他文件组,SQL Server

Jav*_*uzi 5 sql-server partitioning merge

我在 DateTime 列上创建了分区表。过去 6 个月。我在名为“FG_OlderData”的文件组中放置了 3 个最旧的月份,在名为“FG_NewerData”的文件组中放置了 3 个最新的月份。分区函数定义:

CREATE PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange (DateTime)
AS RANGE RIGHT FOR VALUES (
                        -- older_than_current_minus_5
        '20150121', -- current_minus_5
        '20150220', -- current_minus_4
        '20150321', -- current_minus_3
        '20150421', -- current_minus_2
        '20150522', -- current_minus_1
        '20150622',  -- current
        '20150723'  -- Future
)
GO
Run Code Online (Sandbox Code Playgroud)

分区架构定义:

CREATE PARTITION SCHEME ps_Positions_LastSixMonth_MontlyRange
AS PARTITION pf_Positions_LastSixMonth_MonthlyRange
TO (
      FG_OlderData,
      FG_OlderData,
      FG_OlderData,
      FG_OlderData,
      FG_NewerData, -- minus 2 month (to be moved to OlderData)
      FG_NewerData, -- minus 1 month
      FG_NewerData, -- current month
      FG_NewerData  -- future month+
      );
GO
Run Code Online (Sandbox Code Playgroud)

结果 :

OnlineGeoPosition   1   FG_OlderData    0   0   less than   2015-01-21 00:00:00.000
OnlineGeoPosition   2   FG_OlderData    0   0   less than   2015-02-20 00:00:00.000
OnlineGeoPosition   3   FG_OlderData    0   0   less than   2015-03-21 00:00:00.000
OnlineGeoPosition   4   FG_OlderData    0   0   less than   2015-04-21 00:00:00.000
OnlineGeoPosition   5   FG_NewerData    0   0   less than   2015-05-22 00:00:00.000
OnlineGeoPosition   6   FG_NewerData    0   0   less than   2015-06-22 00:00:00.000
OnlineGeoPosition   7   FG_NewerData    0   0   less than   2015-07-23 00:00:00.000
OnlineGeoPosition   8   FG_NewerData    0   0   less than   NULL
Run Code Online (Sandbox Code Playgroud)

首先,我将 (20150522) 分区的数据切换到 temp 能够移动到较旧的文件组:

ALTER TABLE dbo.OnlineGeoPosition
SWITCH PARTITION pf_Positions_LastSixMonth_MonthlyRange('20150522')
TO dbo.OnlineGeoPosition_NewerToOlderTemp;
Run Code Online (Sandbox Code Playgroud)

然后合并切换分区:

ALTER PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange()
    MERGE RANGE ('20150522');
Run Code Online (Sandbox Code Playgroud)

结果 :

OnlineGeoPosition   1   FG_OlderData    0   0   less than   2015-01-21 00:00:00.000
OnlineGeoPosition   2   FG_OlderData    0   0   less than   2015-02-20 00:00:00.000
OnlineGeoPosition   3   FG_OlderData    0   0   less than   2015-03-21 00:00:00.000
OnlineGeoPosition   4   FG_OlderData    0   0   less than   2015-04-21 00:00:00.000
OnlineGeoPosition   5   FG_NewerData    0   0   less than   2015-06-22 00:00:00.000
OnlineGeoPosition   6   FG_NewerData    0   0   less than   2015-07-23 00:00:00.000
OnlineGeoPosition   7   FG_NewerData    0   0   less than   NULL
Run Code Online (Sandbox Code Playgroud)

问题:当我在 OlderData 上拆分 '20150522' 范围时,它保留在 NewerData 文件组中,下一个分区 ('20150622') 转到 OlderData 文件组。

ALTER PARTITION SCHEME ps_Positions_LastSixMonth_MontlyRange
          NEXT USED FG_OlderData;

ALTER PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange()
          SPLIT RANGE ('2015-05-22');
Run Code Online (Sandbox Code Playgroud)

结果 :

OnlineGeoPosition   1   FG_OlderData    0   0   less than   2015-01-21 00:00:00.000
OnlineGeoPosition   2   FG_OlderData    0   0   less than   2015-02-20 00:00:00.000
OnlineGeoPosition   3   FG_OlderData    0   0   less than   2015-03-21 00:00:00.000
OnlineGeoPosition   4   FG_OlderData    0   0   less than   2015-04-21 00:00:00.000
OnlineGeoPosition   5   **FG_NewerData**    0   0   less than   **2015-05-22** 00:00:00.000
OnlineGeoPosition   6   **FG_OlderData**    0   0   less than   **2015-06-22** 00:00:00.000
OnlineGeoPosition   7   FG_NewerData    0   0   less than   2015-07-23 00:00:00.000
OnlineGeoPosition   8   FG_NewerData    0   0   less than   NULL
Run Code Online (Sandbox Code Playgroud)

执行此命令后,我假设 OlderData 文件组上有“2015-05-22”分区,但它保留在 FG_NewerData 文件组中,而下一个分区“20150622”转到 FG_OlderData 文件组。

我的代码有什么问题?如您所见,我使用了 Range Right。

Dan*_*man 5

这里有几个问题。首先,您问题中显示的分区/文件组映射与 DDL 不匹配。一个RANGE RIGHT函数的边界是包容在右边的分区,这样的结果应该是如下匹配DDL。考虑从可以从 SSMS 对象资源管理器表上下文菜单运行的 codeplex 下载分区详细信息自定义报告,以显示边界和文件组:http : //ssmspartcustomrpt.codeplex.com/releases/view/30936

OnlineGeoPosition   1   FG_OlderData    less than                  2015-01-21 00:00:00.000
OnlineGeoPosition   2   FG_OlderData    greater than or equal to   2015-01-21 00:00:00.000
OnlineGeoPosition   3   FG_OlderData    greater than or equal to   2015-02-20 00:00:00.000
OnlineGeoPosition   4   FG_OlderData    greater than or equal to   2015-03-21 00:00:00.000
OnlineGeoPosition   5   FG_NewerData    greater than or equal to   2015-04-21 00:00:00.000
OnlineGeoPosition   6   FG_NewerData    greater than or equal to   2015-05-22 00:00:00.000
OnlineGeoPosition   7   FG_NewerData    greater than or equal to   2015-06-22 00:00:00.000
OnlineGeoPosition   8   FG_NewerData    greater than or equal to   2015-07-23 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

合并RANGE RIGHT函数时,删除的分区是右侧的分区。删除分区中的数据将移动到左侧保留的分区。因此,合并RANGE RIGHT滑动窗口分区总是从新分区移动到旧分区。但是最好是MERGESPLIT空的分区,你正在做的,以避免分区DDL,大约是正常的DML的4倍多昂贵的数据移动。相反,函数SPLIT的 aRANGE RIGHT会在指定边界的右侧创建一个新分区,并在 NEXT 使用的文件组上创建一个新分区,这是您遇到的主要问题。

下面是使用下面的新分区/文件组映射实现滑动窗口的示例脚本。此脚本使用 2 个临时表,一个用于旧数据文件组上的最新分区,另一个用于新数据文件组上的最旧分区(要移动的分区)。这允许边界与两个相邻分区安全地合并为空。您需要检查临时表上的约束或其他分区函数/方案来约束临时表数据以匹配切换的目标分区边界。使用CREATE INDEX...DROP_EXISTING.

OnlineGeoPosition   1   FG_OlderData    less than   2015-02-20 00:00:00.000
OnlineGeoPosition   2   FG_OlderData    greater than or equal to   2015-02-20 00:00:00.000
OnlineGeoPosition   3   FG_OlderData    greater than or equal to   2015-03-21 00:00:00.000
OnlineGeoPosition   4   FG_OlderData    greater than or equal to   2015-04-21 00:00:00.000
OnlineGeoPosition   5   FG_NewerData    greater than or equal to   2015-05-22 00:00:00.000
OnlineGeoPosition   6   FG_NewerData    greater than or equal to   2015-06-22 00:00:00.000
OnlineGeoPosition   7   FG_NewerData    greater than or equal to   2015-07-23 00:00:00.000
OnlineGeoPosition   8   FG_NewerData    greater than or equal to   2015-08-22 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

示例脚本:

--switch out newest partition on FG_OldData
ALTER TABLE dbo.OnlineGeoPosition
SWITCH PARTITION $PARTITION.pf_Positions_LastSixMonth_MonthlyRange('2015-03-21')
TO dbo.OnlineGeoPosition_OlderTemp;

--switch out oldest partition on FG_NewData
ALTER TABLE dbo.OnlineGeoPosition
SWITCH PARTITION $PARTITION.pf_Positions_LastSixMonth_MonthlyRange('2015-04-21')
TO dbo.OnlineGeoPosition_NewerToOlderTemp;

--move empty partition from new data to old data
ALTER PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange()
    MERGE RANGE ('2015-04-21');

--create new empty partition on old data filegroup for moved data
ALTER PARTITION SCHEME ps_Positions_LastSixMonth_MontlyRange
          NEXT USED FG_OlderData;
ALTER PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange()
    SPLIT RANGE ('2015-04-21');

--rebuild each index with drop existing to move data from new to old filegroup
CREATE UNIQUE CLUSTERED INDEX PK_OnlineGeoPosition_NewerToOlderTemp
ON dbo.OnlineGeoPosition_NewerToOlderTemp(PartitioningColumn)
WITH(DROP_EXISTING=ON)
ON FG_OlderData;

--switch staging tables data back in
--staging tables must have a check constraint or be partitoned similarly as the target partition
ALTER TABLE dbo.OnlineGeoPosition_OlderTemp
SWITCH TO dbo.OnlineGeoPosition PARTITION $PARTITION.pf_Positions_LastSixMonth_MonthlyRange('2015-03-21')
ALTER TABLE dbo.OnlineGeoPosition_NewerToOlderTemp
SWITCH TO dbo.OnlineGeoPosition PARTITION $PARTITION.pf_Positions_LastSixMonth_MonthlyRange('2015-04-21')

--remove oldest partition
TRUNCATE TABLE dbo.OnlineGeoPosition_OlderTemp;
ALTER TABLE dbo.OnlineGeoPosition
SWITCH PARTITION $PARTITION.pf_Positions_LastSixMonth_MonthlyRange('2015-01-21')
TO dbo.OnlineGeoPosition_OlderTemp;
TRUNCATE TABLE dbo.OnlineGeoPosition_OlderTemp;
ALTER PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange()
    MERGE RANGE ('2015-01-21');

--create new partition on new data filegroup for future data
ALTER PARTITION SCHEME ps_Positions_LastSixMonth_MontlyRange
          NEXT USED FG_NewerData;
ALTER PARTITION FUNCTION pf_Positions_LastSixMonth_MonthlyRange()
    SPLIT RANGE ('2015-08-22');
GO
Run Code Online (Sandbox Code Playgroud)