【IT168 技术文档】每个月都会有新数据添加到庞大的Orders数据表中,此时如果只对这一个表进行操作,则更新索引的过程将严重制约性能并产生大量碎片。为了进行优化,我们将通过独立的两个表进行配合,即当有新数据产生时,将旧数据从分区表中切换出来,然后将新数据添加到分区表中。
整个过程包含如下几个步骤:
·准备好即将用于存放旧数据的表
·准备好存有新数据的表
·更改分区方案,以便使用新的文件组
·对分区函数进行更改,分裂出新的边界点
注意:前4步均为影响到实际的分区表
·切换进来新数据
·将旧数据切换出去
注意:第5步和第6步的顺序可以进行更改,且更改后执行速度更快
·合并边界点
·备份/删除旧数据
我们实验所用到的分区数据表中包含的数据,因此我们将把数据作为一个分区直接切换进来。当进行分区切换的时候,只有元数据会发生更改,真正的数据并不会产生移动,因此速度非常快。
1.在不影响当前OrdersRange 分区表的前提下,为新数据做好准备
(1)在Solution Explorer 窗口,双击打开Script4 – RollingRangeScenario.sql.
(2)新建一个文件组,用于存放新的数据
ADD FILEGROUP [2004Q3]
GO
(3)为文件组添加一个文件:
ADD FILE
(NAME = N'2004Q3',
FILENAME = N'C:\AdventureWorks2008Test\2004Q3.ndf',
SIZE = 5MB,
MAXSIZE = 100MB,
FILEGROWTH = 5MB)
TO FILEGROUP [2004Q3]
GO
(4)接下来,我们要新建一个未分区的数据表,用于存放分区数据表中新建分区中的数据。该未分区数据表必须与分区数据表具有完全一致的结构和聚集索引。此外,为了能够确保快速进行分区切换,还需要通过约束来确保此未分区数据表中的数据与分区数据表中新建分区的范围相吻合。接下来我们将创建该数据表,插入数据,并创建聚集索引
(
[OrderID] [int] NOT NULL,
[EmployeeID] [int] NULL,
[VendorID] [int] NULL,
[TaxAmt] [money] NULL,
[Freight] [money] NULL,
[SubTotal] [money] NULL,
[Status] [tinyint] NOT NULL ,
[RevisionNumber] [tinyint] NULL,
[ModifiedDate] [datetime] NULL,
[ShipMethodID] tinyint NULL,
[ShipDate] [datetime] NOT NULL,
[OrderDate] [datetime] NOT NULL
CONSTRAINT Orders2004Q3MinDate
CHECK (OrderDate >= '20040701'),
[TotalDue] [money] NULL
) ON [2004Q3]
GO
ALTER TABLE AdventureWorks2008Test.[dbo].[Orders2004Q3]
ADD CONSTRAINT Orders2004Q3MaxDate
CHECK (OrderDate < '20041001')
go
---------------------------------------------
-- Populate new table with Q3 2004 data.
---------------------------------------------
INSERT INTO AdventureWorks2008Test.[dbo].Orders2004Q3
SELECT o.[PurchaseOrderID]
, o.[EmployeeID]
, o.[VendorID]
, o.[TaxAmt]
, o.[Freight]
, o.[SubTotal]
, o.[Status]
, o.[RevisionNumber]
, o.[ModifiedDate]
, o.[ShipMethodID]
, o.[ShipDate]
, o.[OrderDate]
, o.[TotalDue]
FROM AdventureWorks2008.Purchasing.PurchaseOrderHeader AS o
WHERE o.OrderDate >= '20040701'
AND o.OrderDate < '20041001'
GO
---------------------------------------------
-- The table *must* have the same clustered
-- index definition!
---------------------------------------------
CREATE CLUSTERED INDEX Orders2004Q3CLInd
ON Orders2004Q3(OrderDate, OrderID)
ON [2004Q3]
GO
2.为将要进行归档的数据做好准备
存放归档数据的数据表必须与分区数据表具有完全一致的结构和聚集索引。一会儿我们将把文件组2003Q3中的数据进行归档
(1)创建用于归档的数据表:
(
[OrderID] [int] NOT NULL,
[EmployeeID] [int] NULL,
[VendorID] [int] NULL,
[TaxAmt] [money] NULL,
[Freight] [money] NULL,
[SubTotal] [money] NULL,
[Status] [tinyint] NOT NULL ,
[RevisionNumber] [tinyint] NULL,
[ModifiedDate] [datetime] NULL,
[ShipMethodID] tinyint NULL,
[ShipDate] [datetime] NOT NULL,
[OrderDate] [datetime] NOT NULL,
[TotalDue] [money] NULL
) ON [2003Q3]
GO
---------------------------------------------
-- The table must have the same clustered
-- index definition!
---------------------------------------------
CREATE CLUSTERED INDEX Orders2003Q3CLInd
ON Orders2003Q3(OrderDate, OrderID)
ON [2003Q3]
GO
(2)执行如下代码,进行分区切换。注意,此时只是将分区从分区表中移除,数据实际并没有删除,但在OrdersRange 数据表中将无法再看到这些数据,因为这些数据已经被“切换”到了Orders2003Q3 表中
SWITCH PARTITION 2
TO Orders2003Q3
GO
3.验证分区数据表中已经不再包含切换出去的数据
(1)为了确保分区 2中的数据已经被删除,执行如下语句进行查看:
AS 'Parition Number'
, min(OrderDate) AS 'Min Order Date'
, max(OrderDate) AS 'Max Order Date'
, count(*) AS 'Rows In Partition'
FROM OrdersRange
GROUP BY $partition.OrderDateRangePFN(OrderDate)
ORDER BY 1
GO
(2)此时可以看到只有分区3,4,5中有数据
4.删除已经废弃的分区边界
通过刚才所执行的查询我们可以看到,只有分区3,4,5当中有数据,如何才能将所有分区向左移动一位?
此时我们只需要删除最左侧的分区边界
(1)执行如下语句,从OrdersRange 分区表中删除2003年第3季度的分区边界:
MERGE RANGE ('20030701')
GO
(2)此时我们的分区表中将只包含3个有数据的分区和1个空分区。执行如下语句进行核实,注意现在分区2,3,4当中有数据
AS 'Parition Number'
, min(OrderDate) AS 'Min Order Date'
, max(OrderDate) AS 'Max Order Date'
, count(*) AS 'Rows In Partition'
FROM OrdersRange
GROUP BY $partition.OrderDateRangePFN(OrderDate)
ORDER BY 1
GO
(3)Merge操作删除了分区1,因此SQL Server对现有分区进行了重新编号,但并没有移动任何数据,只是改变了分区号。正因如此,数据库所使用的文件组并没有发生改变。执行如下语句进行查询:
(4)之前分区2存放在2003Q3 文件组,但现在该文件组已经不再与该分区表相关联了。执行如下语句,可以查看各个分区及其相关联的文件组:
dds.destination_id AS PartitionNumber,
dds.data_space_id AS FileGroup,
fg.name AS FileGroupName
FROM (((sys.tables AS t
INNER JOIN sys.indexes AS i
ON (t.object_id = i.object_id))
INNER JOIN sys.partition_schemes AS ps
ON (i.data_space_id = ps.data_space_id))
INNER JOIN sys.destination_data_spaces AS dds
ON (ps.data_space_id =
dds.partition_scheme_id))
INNER JOIN sys.filegroups AS fg
ON dds.data_space_id = fg.data_space_id
WHERE (t.name = 'OrdersRange')
AND (i.index_id IN (0,1))
5.将新的文件组添加到分区方案中
前面我们查看了分区表当前的状态,为了添加新的分区(从现有分区当中拆分出来),我们还要为新的分区准备一个存放位置。新的分区将存放在2004Q3 文件组中,该文件组我们前面已经创建。执行如下代码将该文件组添加到分区方案中:
NEXT USED [2004Q3]
GO
6.更改数据表的约束
分区视图非常依赖约束,而分区数据表对约束的依赖没有这么强。但出于数据完整性的考虑,此实验中我们为数据表添加了约束。现有约束只允许添加2003Q3 到2004Q2之间的数据。为了能够将新数据切换到分区表中,我们首先要更改此约束
(1)执行如下代码,更改分区表的约束:
ADD CONSTRAINT OrdersRangeMax
CHECK ([OrderDate] < '20041001')
go
ALTER TABLE OrdersRange
ADD CONSTRAINT OrdersRangeMin
CHECK ([OrderDate] >= '20031001')
go
ALTER TABLE OrdersRange
DROP CONSTRAINT OrdersRangeYear
go
(2)接下来执行下面的代码,分裂出新的分区:
SPLIT RANGE ('20040701')
GO
(3)将数据切换到新的分区中:
SWITCH TO OrdersRange PARTITION 5
GO
(4)最后验证数据:
AS 'Parition Number'
, min(OrderDate) AS 'Min Order Date'
, max(OrderDate) AS 'Max Order Date'
, count(*) AS 'Rows In Partition'
FROM OrdersRange
GROUP BY $partition.OrderDateRangePFN(OrderDate)
ORDER BY 1
GO
(5)关闭Script4 - RollingRangeScenario.sql.