在 SQL 2014 中拆分现有分区

Phi*_*lip 2 sql-server partitioning sql-server-2014

我有一个包含超过 200 亿行的 SQL Server 表,最后一个分区中有 130 亿行。

该表目前按“时间”字段分为 6 种方式:

2011
2012
2013
2014
2015
2016/2017/2018
Run Code Online (Sandbox Code Playgroud)

2016/2017/2018分区需要拆分成自己的分区所以有2016、2017、2018分区。

如何做到这一点并在此过程中避免大量日志文件增长?数据库处于简单恢复中,当前每个分区都位于其自己的一组磁盘上的单独文件组中。

CREATE TABLE [dbo].[Log](

      [RefNo] [nchar](7) NOT NULL,

      [DevID] [nvarchar](7) NOT NULL,

      [Time] [datetime] NOT NULL,

      [summary] [float] NULL,

      [staging] [float] NULL,

      [position] [float] NULL,

CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED

(

      [RefNo] ASC,

      [DevID] ASC,

      [Time] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 96)

)
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

Dan*_*man 6

下面是创建新的年度分区的示例脚本。您可能需要针对实际分区函数名称和新文件组名称调整脚本。此方法假定操作是在维护窗口中执行的,此时表中没有插入操作,并且查询不需要 2016 年及以后的数据。

脚本执行的步骤总结如下:

  • 像原来一样创建新的分区函数和方案
  • 像原来一样创建新的对齐临时表
  • 将包含数据 > 2016-01-01 的分区切换到暂存表中
  • 将 3 个新分区添加到原始分区函数/方案
  • 使用 DROP_EXISTING=ON 在原始分区上重建临时表
  • 将 3 个新分区从临时表切换回原始表

您应该注意现有表分区存在的一些问题。由于该RANGE LEFT功能,正好是一年中第一天午夜的日期时间值将被放置在错误的分区中。例如,Time值为 '2012-01-01T00:00:00' 的行将与 2011 年数据一起位于分区 1 中,而不是分区 2 中包含 2012 年剩余时间的数据。除非您按分区清除数据,否则这可能不是问题。

请注意,如果RANGE LEFT永远无法删除功能,则最后一个分区。这意味着最后一个分区的文件组是使用该功能的分区方案的永久组成部分。在您的情况下,文件组Year6FileGroup将始终是psYearlyPartition_Log方案的最后一个文件组,尽管它也可以用于另一个分区,例如此处的 2016 年。

脚本运行后的分区如下所示,预计最后一个分区将为空(假设您没有未来年份的数据)。您应该在年初之前创建下一年的分区,以避免拆分非空分区或避免再次跳过这些箍。

+------------------+----------------+----------------+----------------+
| Partition Number | Lower Boundary | Upper Boundary |   Filegroup    |
+------------------+----------------+----------------+----------------+
|                1 | NULL           | <= 2012-01-01  | Year1FileGroup |
|                2 | > 2012-01-01   | <= 2013-01-01  | Year2FileGroup |
|                3 | > 2013-01-01   | <= 2014-01-01  | Year3FileGroup |
|                4 | > 2014-01-01   | <= 2015-01-01  | Year4FileGroup |
|                5 | > 2015-01-01   | <= 2016-01-01  | Year5FileGroup |
|                6 | > 2016-01-01   | <= 2017-01-01  | Year6FileGroup |
|                7 | > 2017-01-01   | <= 2018-01-01  | Year7FileGroup |
|                8 | > 2018-01-01   | <= 2019-01-01  | Year8FileGroup |
|                9 | > 2019-01-01   | NULL           | Year6FileGroup |
+------------------+----------------+----------------+----------------+
Run Code Online (Sandbox Code Playgroud)

我通常RANGE RIGHT在对诸如日期时间之类的增量值进行分区时推荐一个函数,因为这种行为更直观。有关此和其他注意事项,请参阅表分区最佳实践

--create identical partition function and scheme
CREATE PARTITION FUNCTION pfYearlyPartition_Log_Staging(datetime) 
    AS RANGE LEFT FOR VALUES(
      '20120101'
    , '20130101'
    , '20140101'
    , '20150101'
    , '20160101'
);
CREATE PARTITION SCHEME psYearlyPartition_Log_Staging
    AS PARTITION pfYearlyPartition_Log_Staging TO (
      Year1FileGroup
    , Year2FileGroup
    , Year3FileGroup
    , Year4FileGroup
    , Year5FileGroup
    , Year6FileGroup
);

--create identical aligned staging table
CREATE TABLE [dbo].[Log_Staging](
      [RefNo] [nchar](7) NOT NULL,
      [DevID] [nvarchar](7) NOT NULL,
      [Time] [datetime] NOT NULL,
      [summary] [float] NULL,
      [staging] [float] NULL,
      [position] [float] NULL,
CONSTRAINT [PK_Log_Staging] PRIMARY KEY CLUSTERED
(
      [RefNo] ASC,
      [DevID] ASC,
      [Time] ASC
) 
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 96)
) ON psYearlyPartition_Log_Staging(Time);

--switch last partition into staging table
ALTER TABLE dbo.Log
    SWITCH PARTITION $PARTITION.pfYearlyPartition_Log('20170101')
    TO dbo.Log_Staging PARTITION $PARTITION.pfYearlyPartition_Log_Staging('20170101');

--create new partitions for main table (assuming filegroups already exist for years 7 and 8)
ALTER PARTITION SCHEME psYearlyPartition_Log
    NEXT USED Year6FileGroup;
ALTER PARTITION FUNCTION pfYearlyPartition_Log()
    SPLIT RANGE('20170101');
ALTER PARTITION SCHEME psYearlyPartition_Log
    NEXT USED Year7FileGroup;
ALTER PARTITION FUNCTION pfYearlyPartition_Log()
    SPLIT RANGE('20180101');
ALTER PARTITION SCHEME psYearlyPartition_Log
    NEXT USED Year8FileGroup;
ALTER PARTITION FUNCTION pfYearlyPartition_Log()
    SPLIT RANGE('20190101');

--we must specify IGNORE_DUP_KEY=OFF in order to use DROP_EXISTING_ON here
--but, since the original table PK index definition is unchanged, that's a non-issue
CREATE UNIQUE CLUSTERED INDEX [PK_Log_Staging] ON dbo.Log_Staging 
(
      [RefNo] ASC,
      [DevID] ASC,
      [Time] ASC
) 
WITH (DROP_EXISTING=ON, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 96)
ON psYearlyPartition_Log(Time);

ALTER TABLE dbo.Log_Staging
    SWITCH PARTITION $PARTITION.pfYearlyPartition_Log('20170101')
    TO dbo.Log PARTITION $PARTITION.pfYearlyPartition_Log('20170101');
ALTER TABLE dbo.Log_Staging
    SWITCH PARTITION $PARTITION.pfYearlyPartition_Log('20180101')
    TO dbo.Log PARTITION $PARTITION.pfYearlyPartition_Log('20180101');
ALTER TABLE dbo.Log_Staging
    SWITCH PARTITION $PARTITION.pfYearlyPartition_Log('20190101')
    TO dbo.Log PARTITION $PARTITION.pfYearlyPartition_Log('20190101');
Run Code Online (Sandbox Code Playgroud)