归档除当前年份以外的所有数据并同时对表进行分区的最佳方法是什么

Ken*_*her 24 sql-server architecture sql-server-2008-r2 archive

任务

从一组大表中归档除滚动 13 个月之外的所有内容。存档数据必须存储在另一个数据库中。

  • 数据库处于简单恢复模式
  • 这些表从 5000 万行到几十亿行,在某些情况下每个表占用数百 GB。
  • 表当前未分区
  • 每个表在不断增加的日期列上都有一个聚集索引
  • 每个表额外有一个非聚集索引
  • 对表的所有数据更改都是插入
  • 目标是最大限度地减少主数据库的停机时间。
  • 服务器是 2008 R2 Enterprise

“归档”表将有大约 11 亿行,“活”表大约有 4 亿行。显然存档表会随着时间的推移而增加,但我希望活动表也能合理快速地增加。至少在接下来的几年里说 50%。

我曾考虑过 Azure 扩展数据库,但不幸的是我们在 2008 R2 并且可能会在那里停留一段时间。

当前计划

  • 创建一个新的数据库
  • 在新数据库中创建按月(使用修改日期)分区的新表。
  • 将最近 12-13 个月的数据移动到分区表中。
  • 对两个数据库进行重命名交换
  • 从现在的“归档”数据库中删除移动的数据。
  • 对“归档”数据库中的每个表进行分区。
  • 将来使用分区交换来归档数据。
    • 我确实意识到我必须换出要存档的数据,将该表复制到存档数据库,然后将其交换到存档表中。这是可以接受的。

问题: 我正在尝试将数据移动到初始分区表中(实际上我仍在对其进行概念验证)。我正在尝试使用 TF 610(根据数据加载性能指南)和一个INSERT...SELECT语句来移动数据,最初认为它会被最少记录。不幸的是,每次我尝试它都被完全记录。

在这一点上,我认为我最好的选择可能是使用 SSIS 包移动数据。我试图避免这种情况,因为我正在处理 200 个表,并且我可以通过脚本轻松生成和运行任何我可以做的事情。

我的总体计划中是否遗漏了任何内容,SSIS 是快速移动数据和最少使用日志(空间问题)的最佳选择吗?

没有数据的演示代码

-- Existing structure
USE [Audit]
GO

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
); 
-- ~1.4 bill rows, ~20% in the last year

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(   [Modified] ASC   )
GO


-- New DB & Code
USE Audit_New
GO

CREATE PARTITION FUNCTION ThirteenMonthPartFunction (datetime)
AS RANGE RIGHT FOR VALUES ('20150701', '20150801', '20150901', '20151001', '20151101', '20151201', 
                            '20160101', '20160201', '20160301', '20160401', '20160501', '20160601', 
                            '20160701') 

CREATE PARTITION SCHEME ThirteenMonthPartScheme AS PARTITION ThirteenMonthPartFunction
ALL TO ( [PRIMARY] );

CREATE TABLE [dbo].[AuditTable](
    [Col1] [bigint] NULL,
    [Col2] [int] NULL,
    [Col3] [int] NULL,
    [Col4] [int] NULL,
    [Col5] [int] NULL,
    [Col6] [money] NULL,
    [Modified] [datetime] NULL,
    [ModifiedBy] [varchar](50) NULL,
    [ModifiedType] [char](1) NULL
) ON ThirteenMonthPartScheme (Modified)
GO

CREATE CLUSTERED INDEX [AuditTable_Modified] ON [dbo].[AuditTable]
(
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO

CREATE NONCLUSTERED INDEX [AuditTable_Col1_Col2_Col3_Col4_Modified] ON [dbo].[AuditTable]
(
    [Col1] ASC,
    [Col2] ASC,
    [Col3] ASC,
    [Col4] ASC,
    [Modified] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON ThirteenMonthPartScheme (Modified)
GO
Run Code Online (Sandbox Code Playgroud)

移动代码

USE Audit_New
GO
DBCC TRACEON(610);

INSERT INTO AuditTable
SELECT * FROM Audit.dbo.AuditTable
WHERE Modified >= '6/1/2015'
ORDER BY Modified
Run Code Online (Sandbox Code Playgroud)

Geo*_*son 11

为什么您没有获得最少的日志记录?

我发现您参考的Data Loading Performance Guide是非常宝贵的资源。然而,它也不是 100% 全面的,我怀疑网格已经足够复杂,作者没有添加列Table Partitioning来根据接收插入的表是否分区来打破行为差异。正如我们稍后将看到的,表已经分区的事实似乎抑制了最小日志记录。

在此处输入图片说明

推荐方法

根据数据加载性能指南中的建议(包括“批量加载分区表”部分)以及加载具有数百亿行的分区表的丰富经验,以下是我推荐的方法:

  • 创建一个新的数据库。
  • 在新数据库中创建按月分区的新表。
  • 按以下方式移动最近一年的数据:
    • 每个月,创建一个新的堆表;
    • 使用 TABLOCK 提示将该月的数据插入到堆中;
    • 将聚集索引添加到包含该月数据的堆中;
    • 添加检查约束,强制该表只包含本月的数据;
    • 将表切换到新的整体分区表对应的分区。
  • 对两个数据库进行重命名交换。
  • 截断现在“归档”数据库中的数据。
  • 对“归档”数据库中的每个表进行分区。
  • 将来使用分区交换来归档数据。

与您的原始方法相比的差异:

  • 如果以TABLOCK一个月一次的速度加载到堆中,使用分区切换将数据放入分区表中,那么移动最近 12-13 个月的数据的方法将更加高效。
  • ADELETE清除旧表将被完全记录。也许您可以TRUNCATE或者删除该表并创建一个新的存档表。

移动最近一年数据的方法比较

为了在我的机器上在合理的时间内比较方法,我使用了100MM row我生成的并遵循您的架构的测试数据集。

从下面的结果中可以看出,通过使用TABLOCK提示将数据加载到堆中,可以大大提高性能并减少日志写入。如果一次完成一个分区,还有一个额外的好处。还值得注意的是,如果您一次运行多个分区,则一次一个分区的方法可以轻松地进一步并行化。根据您的硬件,这可能会带来不错的提升;我们通常在服务器级硬件上一次加载至少四个分区。

在此处输入图片说明

这是完整的测试脚本

最后的笔记

所有这些结果都在某种程度上取决于您的硬件。但是,我的测试是在带有旋转磁盘驱动器的标准四核笔记本电脑上进行的。如果您使用的是在执行此过程时没有大量其他负载的不错的服务器,则数据加载速度可能会快得多。

例如,我在实际的开发服务器 (Dell R720) 上运行推荐的方法并看到减少到76 seconds(从156 seconds我的笔记本电脑上)。有趣的是,插入分区表的原始方法没有经历相同的改进,并且仍然12 minutes在开发服务器上接管。大概这是因为这种模式产生了一个串行执行计划,我笔记本电脑上的单个处理器可以匹配开发服务器上的单个处理器。