SQL Server 2005 如何创建分区表
SQL Server 2005 如何创建分区表?
确定是否应为对象分区
虽然分区可以带来众多的好处,但也增加了实现对象的管理费用和复杂性,这可能是得不偿失的。尤其是,您可能不需要为较小的表或目前满足性能和维护要求的表分区。前面提到的销售方案使用分区减轻了移动行和数据的负担,但在决定是否实现分区时,您应考虑您的方案是否存在这种负担。
确定分区键和分区数
如果您正在尝试改善大型数据子集的性能和可管理性,并且已经定义了访问模式,则可以使用范围分区减少数据争用的情况,同时减少只读数据不需要分区时的维护工作。要确定分区数,应先评估您的数据中是否存在逻辑分组和模式。如果您通常一次只处理这些已定义子集中的少数几个,则应定义范围以隔离查询,使其只处理相应的数据(即:只处理特定的分区)。
确定是否应使用多个文件组
为了有助于优化性能和维护,应使用文件组分离数据。文件组的数目一定程度上由硬件资源决定:一般情况下,文件组数最好与分区数相同,并且这些文件组通常位于不同的磁盘上。但是,这主要适用于打算对整个数据集进行分析的系统。如果您有多个 CPU,SQL Server 则可以并行处理多个分区,从而大大缩短处理大量复杂报表和分析的总体时间。这种情况下,可以获得并行处理以及在分区表中移入和移出分区的好处。
创建文件组
如果需要为多个文件放置一个分区表以获得更好的 I/O 平衡,则至少需要创建一个文件组。文件组可以由一个或多个文件构成,而每个分区必须映射到一个文件组。一个文件组可以由多个分区使用,但是为了更好地管理数据(例如,为了获得更精确的备份控制),应该对分区表进行设计,以便只有相关数据或逻辑分组的数据位于同一个文件组中。使用 ALTER DATABASE,可以添加逻辑文件组名,然后添加文件。要为 AdventureWorks 数据库创建名为 2003Q3 的文件组,请按以下方式使用 ALTER DATABASE:
ALTER DATABASE AdventureWorks ADD FILEGROUP [2003Q3]
创建文件组后,使用 ALTER DATABASE 将文件添加到该文件组中。
通过在 CREATE TABLE 的 ON 子句中指定一个文件组,可以为文件创建一个表。但是,如果表未分区,则不能为多个文件组创建一个表。要为一个文件组创建表,请使用 CREATE TABLE 的 ON 子句。要创建分区表,必须先确定分区的功能机制。进行分区的标准以分区函数的形式从逻辑上与表相分离。此分区函数作为独立于表的定义存在,而这种物理分离将起到帮助作用,因为多个对象都可以使用该分区函数。因此,为表分区的第一步是创建分区函数。
为范围分区创建分区函数
范围分区必须使用边界条件进行定义。而且,即使通过 CHECK 约束对表进行了限制,也不能消除该范围任一边界的值。为了允许定期将数据移入该表,需要创建最后一个空分区。
在范围分区中,首先定义边界点:如果存在五个分区,则定义四个边界点值,并指定每个值是第一个分区的上边界 (LEFT) 还是第二个分区的下边界 (RIGHT)。根据 LEFT 或 RIGHT 指定,始终有一个空分区,因为该分区没有明确定义的边界点。
具体来讲,如果分区函数的第一个值(或边界条件)是 '20001001',则边界分区中的值将是:
对于 LEFT 第一个分区是所有小于或等于 '20001001' 的数据 第二个分区是所有大于 '20001001' 的数据 对于 RIGHT 第一个分区是所有小于 '20001001' 的数据 第二个分区是所有大于或等于 '20001001' 数据
由于范围分区可能在 datetime 数据中进行定义,因此必须了解其含义。使用datetime具有某种含义:即总是同时指定日期和时间。未定义时间值的日期表示时间部分为“0”的 12:00 A.M。如果将 LEFT 与此类数据结合使用,则日期为 10 月 1 日 12:00 A.M. 的数据将位于第一个分区,而 10 月份的其他数据将位于第二个分区。从逻辑上讲,最好将开始值与 RIGHT 结合使用,而将结束值与 LEFT 结合使用。下面的三个子句将创建逻辑上相同的分区结构
注意:此处使用 datetime 数据类型确实增加了一定的复杂性,但您需要确保设置正确的边界情况。请注意使用 RIGHT 的简单性,因为默认时间为 12:00:00.000 A.M。对于 LEFT,复杂性增加是因为 datetime 数据类型具有精度。必须选择 23:59:59.997 的原因在于,datetime 数据无法保证毫秒级别的精度。相反,datetime 数据的精度在 3.33 毫秒内。使用 23:59:59.999 这个确切的时间值是不行的,因为该值将被舍入到最接近的时间值,即第二天的 12:00:00.000 A.M。由于进行了这种舍入,将无法正确定义边界。对于 datetime 数据,必须对明确提供的毫秒值加倍小心。
注意:分区函数还允许将函数作为分区函数定义的一部分。您可以使用 DATEADD(ms,-3,'20010101'),而不是使用 '20001231 23:59:59.997' 明确定义时间。
要在四个活动分区(每个分区代表一个日历季度)中存储四分之一的 Orders 数据,并创建第五个分区以备将来使用(还是作为占位符,用于在分区表中移入和移出数据),请将 LEFT 分区函数与以下四个边界条件结合使用:
记住,定义四个边界点将创建五个分区。通过查看以下数据集检查此分区创建的数据集:
边界点 '20000930 23:59:59.997' 作为 LEFT(设置模式): 最左侧的分区将包含所有小于或等于 '20000930 23:59:59.997' 的值 边界点 '20001231 23:59:59.997': 第二个分区将包含所有大于 '20000930 23:59:59.997' 但小于或等于 '20001231 23:59:59.997' 的值 边界点 '20010331 23:59:59.997': 第三个分区将包含所有大于 '20001231 23:59:59.997' 但小于或等于 '20010331 23:59:59.997' 的值 边界点 '20010630 23:59:59.997': 第四个分区将包含所有大于 '20010331 23:59:59.997' 但小于或等于 '20010630 23:59:59.997' 的值 最后,第五个分区将包含所有大于 '20010630 23:59:59.997' 的值。
创建分区架构
创建分区函数后,必须将其与分区架构相关联,以便将分区定向至特定的文件组。定义分区架构时,即使多个分区位于同一个文件组中,也必须为每个分区指定一个文件组。对于前面创建的范围分区 (OrderDateRangePFN),存在五个分区;最后一个空分区将在 PRIMARY 文件组中创建。因为此分区永远不包含数据,所以不需要指定特殊的位置。
创建分区表
定义分区函数(逻辑结构)和分区架构(物理结构)后,即可创建表来利用它们。表定义应使用的架构,而架构又定义函数。要将这三者结合起来,必须指定应该应用分区函数的列。范围分区始终只映射到表中的一列,此列应与分区函数中定义的边界条件的数据类型相匹配。另外,如果表应明确限制数据集(而不是从负无穷大到正无穷大),则还应添加 CHECK 约束。
建立索引:是否分区?
默认情况下,分区表中创建的索引也使用相同的分区架构和分区列。如果属于这种情况,索引将与表对齐。尽管未作要求,但将表与其索引对齐可以使管理工作更容易进行,对于滑动窗口方案尤其如此。
例如,要创建唯一的索引,分区列必须是一个关键列;这将确保对相应的分区进行验证,以保证索引的唯一性。因此,如果需要在一列上对表进行分区,而必须在另一个列上创建唯一的索引,这些表和索引将无法对齐。在这种情况下,可以在唯一的列(如果是多列的唯一键,则可以是任一关键列)中对索引进行分区,或者根本就不进行分区。请注意,在分区表中移入和移出数据时,必须删除和创建此索引。
注意:如果您打算使用现有数据加载表并立即在其中添加索引,则通常可以通过以下方式获得更好的性能:先加载到未分区、未建立索引的表中,然后在加载数据后创建分区索引。通过为分区架构定义群集索引,可以在加载数据后更有效地为表分区。这也是为现有表分区的不错方法。要创建与未分区表相同的表并创建与已分区群集索引相同的群集索引,请用一个文件组目标位置替换创建表中的 ON 子句。然后,在加载数据之后为分区架构创建群集索引
SQL Server 2005 分区表实践——建立分区表(partition table)
问题:有一个订单表 Orders,要转换成分区表,以订单日期 OrderDate 为分区列,目前含有订单日期为 1996-07-04~1998-05-06 的数据。可以在 SQL Server 2000 Northwind 数据库中找到 Orders 表,下面是简化了的表结构:
createtable dbo.Orders
(
OrderID int notnull
,CustomerID varchar(10) notnull
,EmployeeID int notnull
,OrderDate datetime notnull
,constraint PK_Orders primarykey noclustered (OrderID, CustomerID)
)
go
createclusteredindex IXC_Orders_OrderDate on dbo.Orders(OrderDate)
go
1. 创建分区函数(partition function)
在创建分区函数的时候,我一般这样命名分区函数:'PF'+Table Name + 分区字段名 +'Range',例如:'PF_Orders_OrderDateRange',如果字段名较长的话,则可以省略去,可以这样命名: 'PF_Orders_DateRange'
create partition function PF_Orders_OrderDateRange(datetime)
as
range rightforvalues (
'1997-01-01',
'1998-01-01',
'1999-01-01'
)
go
分区函数 'PF_Orders_OrderDateRange' 有 3 个边界值('1997-01-01', '1998-01-01', '1999-01-01'),这三个边界值(boundary value)组成了 4 个分区(partition),并且 “range right” 表明边界值属于右边的分区。下面使用存储过程 dbo.sp_show_partition_range 来查看分区范围:
exec dbo.sp_show_partition_range @partition_function='PF_Orders_OrderDateRange'
partition_function partition minval value maxval
------------------------- ----------- ------------------------- -------- ------------------------
PF_Orders_OrderDateRange 1 NULL <= val < 1997-01-0100:00:00.000
PF_Orders_OrderDateRange 2 1997-01-0100:00:00.000 <= val < 1998-01-0100:00:00.000
PF_Orders_OrderDateRange 3 1998-01-0100:00:00.000 <= val < 1999-01-0100:00:00.000
PF_Orders_OrderDateRange 4 1999-01-0100:00:00.000 <= val < NULL
每个分区的最大值和最小值,一清二楚。获得 dbo.sp_show_partition_range 代码。
2. 创建分区方案(partition scheme)
分区方案定义了,分区表或者分区索引的每个分区的数据存放在哪个文件组上。试想,如果没有分区方案的话,如何实现把分区表中不同的分区存放在不同的文件组上?我们可以看下创建普通数据表的语法:
createtable[table name] ... on[filegroup]
显然,普通表整个表的数据,只能存放在同一个文件组上。为了实现分区机制,才引入了分区方案这个概念。每个分区表只属于一个方案(scheme),因此分区方案可以这样命名:'PS'+Table Name
create partition scheme PS_Orders
as
partition PF_Orders_OrderDateRange
to ([primary], [primary], [primary], [primary])
go
分区方案 PS_Orders 规定了,把分区表的 4 个分区分别存放在主文件组 primary 上。分区方案中指定的文件组数目,不能少于分区函数中划定的分区数目;但可以多于分区函数中划定的分区数目。多出的第 1 个文件组用来指定当分区表增加分区时,下一个分区所使用的文件组;多出的其他文件组将被忽略。
下面的例子,分区方案指定了 5 个文件组(多出了 1 个文件组)。
drop partition scheme PS_Orders
go
create partition scheme PS_Orders
as
partition PF_Orders_OrderDateRange
to ([primary], [primary],[primary], [primary],[primary])
go
Partition scheme 'PS_Orders' has been created successfully.
'PRIMARY'is marked as the next used filegroup in partition scheme 'PS_Orders'.
下面的例子,分区方案指定了 7 个文件组(多出了 3 个文件组)。
drop partition scheme PS_Orders
go
create partition scheme PS_Orders
as
partition PF_Orders_OrderDateRange
to ([primary], [primary],[primary], [primary],[primary],[primary],[primary])
go
Partition scheme 'PS_Orders' has been created successfully.
'PRIMARY'is marked as the next used filegroup in partition scheme 'PS_Orders'.
2 filegroup specified after the next used filegroup are ignored.
如果分区表所有的分区都将分配在同一个文件组 [primary] 上,那么可以使用下面更简洁的方法:
drop partition scheme PS_Orders
go
create partition scheme PS_Orders
as
partition PF_Orders_OrderDateRange
allto ([primary])
go
3. 创建分区表(partition table)
创建了分区函数和分区方案,准备工作做完了,现在终于可以开始创建分区表了。创建分区表和普通表的语法大致相同,不同之处:普通表需要指定所存放的文件组,分区表需要指定分区方案。
createtable dbo.Orders
(
OrderID int notnull
,CustomerID varchar(10) notnull
,EmployeeID int notnull
,OrderDate datetime notnull
)
on PS_Orders(OrderDate)
go
根据订单表 Orders 查询时经常使用 OrderDate 范围条件来查询的特点,我们最好在 Orders.OrderDate 列上建立聚集索引(clusteredindex)。为了便于进行分区切换(partition swtich),大多数情况下,建议在分区表上建立分区索引。下面建立聚集分区索引:
createclusteredindex IXC_Orders_OrderDate on dbo.Orders(OrderDate)
on PS_Orders(OrderDate)
如果没有指定 “on PS_Orders(OrderDate)”,默认建立的聚集索引和分区表的分区方案相同。
另外 Orders 分区表需要在(OrderID, CustomerID)上建立主键。我们知道主键实际上是个唯一索引,但分区表在建立唯一索引(分区索引)的时候,分区列必须是唯一索引的一部分。为什么要这样子呢?因为 SQL Server 不但要保证索引在各个分区是唯一的,还要保证在整个表中是唯一的。
altertable dbo.Orders addconstraint PK_Orders primarykey (OrderID, CustomerID, OrderDate)
如果不指定 OrderDate 的话,则会出现错误:1908
Msg 1908, Level16, State 1, Line 1
Column'OrderDate'is partitioning columnof the index'PK_Orders'.
Partition columns for a uniqueindex must be a subset of the indexkey.
Msg 1750, Level16, State 0, Line 1
Could notcreateconstraint. See previous errors.
查看分区表 Orders 上的索引:
exec sp_helpindex 'dbo.Orders'
index_name index_description index_keys
--------------------- ------------------------------------------------------ ------------------------------
IXC_Orders_OrderDate clustered located on PS_Orders OrderDate
PK_Orders nonclustered, unique, primarykey located on PS_Orders OrderID, CustomerID, OrderDate
4. 向分区表中填充数据
insertinto dbo.Orders
select OrderID, CustomerID, EmployeeID, OrderDate
from dbo.Orders_From_SQL2000_Northwind
数据表 dbo.Orders_From_SQL2000_Northwind,是从 SQL Server 2000 中 Northwind.Orders 迁移过来的。
5. 查看分区表各分区数据情况(数据行数,最大最小 OrderDate 值)
select partition = $partition.PF_Orders_OrderDateRange(OrderDate)
,rows =count(*)
,minval =min(OrderDate)
,maxval =max(OrderDate)
from dbo.Orders
groupby $partition.PF_Orders_OrderDateRange(OrderDate)
orderby partition
partition rows minval maxval
----------- ----------- ----------------------- -----------------------
1 152 1996-07-0400:00:00.0001996-12-3100:00:00.000
2 408 1997-01-0100:00:00.0001997-12-3100:00:00.000
3 270 1998-01-0100:00:00.0001998-05-0600:00:00.000
(3 row(s) affected)
从以上结果集中可以看出:分区表 Orders 的 3 个分区中已经填入了数据。这里要注意 $partition.partition_function_name(expression) 这个函数,或许像我一样:一辈子没见过这样的函数:)
把原有的数据库表切换为分区表
USE tempdb
GO
-- 测试表
CREATETABLE dbo.tb(
id int,
CONSTRAINT PK_id PRIMARYKEYCLUSTERED(
id)
)
INSERT dbo.tb
SELECT1UNIONALL
SELECT10
GO
-- 切换为分区表
-- 分区函数
CREATE PARTITION FUNCTION PF_test(int)
AS RANGE LEFT
FORVALUES(5)
-- 分区架构
CREATE PARTITION SCHEME PS_test
AS PARTITION PF_test
ALLTO(
[PRIMARY])
-- 切换到分区表
ALTERTABLE dbo.tb
DROPCONSTRAINT PK_id
WITH(
MOVE TO PS_test(id))
本文由 www.sqlstudy.com 原创,版权所有,转载请注明作者和出处!
本文链接:http: