zSqlServer2005分区表学习总结
数据库结构和索引的是否合理在很大程度上影响了数据库的性能,但是随着数据库信息负载的增大,对数据库的性能也发生了很大的影响。可能我们的数据库在一开始有着很高的性能,但是随着数据存储量的急 速增长—例如订单数据—数据的性能也受到了极大的影响,一个很明显的结果就是查询的反应会非常慢。在这个时候,除了你可以优化索引及查询外,你还可以做什么?
案例:
2008年秋天的某天,某公司的一个团队接到成都市XX局一个SQL调优的ESS单子。客户反映查询统计一次各地市局上报的数据汇总,需要6到15秒才能获得真正想要的数据,当工程师销售人员赶到客户数据中心现场后 发现里面布置了很多柜式服务器,每台服务器都是8核16G内存。和相关技术负责人沟通以及演示业务系之后,可以肯定不是服务器性能的问题,工程师详细分析了他们的数据库,统计慢的几张表往往一周的上报数 便会增加1百多万行,导致他们这个系统刚上线没多久,某些表产生的数据已经在2000万行以上,最终提出了优化方案,业务逻辑层采用存储过程代替普通的SQL语句,并启用相关开发平台的缓存技术;数据系统中采用增强索引和规划分区表进行优化,最终问题解决。 一、 什么是分区表?
分区表是把数据按某种标准划分成区域存储在不同的文件组中,使用分区可以快速而有
效地管理和访问 数据子集,从而使大型表或索引更易于管理。合理的使用分区会很大程度上提高数据库的性能。已分区表和 已分区索引的数据划分为分布于一个数据库中多个文件组的单元。数据是按水平方式分区的,因此多组行映 射到单个的分区。已分区表和已分区索引支持与设计和查询标准表和索引相关的所有属性和功能,包括约 束、默认值、标识和时间戳值以及触发器。因为分区表的本质是把符合不同标准的数据子集存储在一个数据 库的一个或多个文件组中,通过元数据来表述数据存储逻辑地址。
决定是否实现分区主要取决于表当前的大小或将来的大小、如何使用表以及对表执行用
户查询和维护操作的完善程度。通常,如果某个大型表同时满足下列两个条件,则可能适于进行分区:
1. 该表包含(或将包含)以多种不同方式使用的大量数据。
2. 不能按预期对表执行查询或更新,或维护开销超过了预定义的维护期。 使用分区表有如下好处:
1. 提高数据的高用性,可用性的提高源自每个分区的独立性,优化器知道这种分区机
制,会相应的从查询计划中除去未引用的分区。
2. 减轻管理员负担。
3. 改善某些查询性能,在只读查询的性能方面,分区对两类操作起作用。
? 分区消除:处理查询时,不考虑某些分区。 ? 并行操作:并行全表扫描和并行索引区间扫描。 4. 减少资源竞争。
下图是分区表的示意图:
例如,如果对当前年份或当前月份的数据主要执行 SELECT 、INSERT、UPDATE 和 DELETE 操作,而对以前年份或以前月份的数据主要执行 SELECT 查询,则如果按年份或月份对表进行分区,表的管理要容易些,因为此时对表的维护操作只针对一个数据子集。如果该表没有分区,那么就需要对整个数据集执行这些操作,这样就会消耗大量资源。
使用分区表的主要目的,是为了改善大型表以及具有各种访问模式的表的可伸缩性和可管理性。 分区一方面可以将数据分为更小、更易管理的部分,为提高性能起到一定的作用;另一方面,对于如果具有多个CPU的系统,分区可以对表的操作通过并行的方式进行,这对于提升性能是非常有帮助的。
一般而言,衡量大型表是以数据为标准的,但对于适合分区的大型表,衡量大型表更重要的是对数据访问的性能,如果对于某些表的访问和维护有较严重的性能问题,就可以视为大型表,就应该考虑通过更好的设计和分区来解决性能问题。 二、 如何创建分区表?
创建分区表需要以下三个步骤: 1. 创建分区函数。
2. 创建映射到分区函数的分区方案。 3. 创建使用分区方案的分区表。 分区函数:
分区函数是数据库中的一个独立对象,它将表的行映射到一组分区,所以分区函数解决的是HOW的问题,即表如何分区的问题。创建分区函数时,必须指明数据分区的边界点以及分区依据列,这样便知道如何 对表或索引进行分区。分区函数的创建语法如下:
CREATE PARTITION FUNCTION partition_function_name ( input_parameter_type ) AS RANGE [LEFT | RIGHT]
FOR VALUES ( [ boundary_value [ ,...n ] ] ) 语法解释:
创建一个分区函数和创建一个普通的数据库对象(例如表)没什么区别。 partition_function_name是分区函数的名称。分区函数名称在数据库内必须唯一,并且符合标识符的规则。
input_parameter_type是用于分区的列的数据类型,习惯把它称为分区依据列。当用作分区列时,除 text、ntext、image、xml、timestamp、varchar(max)、nvarchar(max)、varbinary(max)、别名数据类型或 CLR 用户定义数据类型外,其他所有数据类型均有效。分区依据列是在 CREATE T ABLE 或 CREATE INDEX 语句中指定的。
boundary_value [ ,...n ]中的boundary_value是边界值(或边界点的值),n代表可以最多有n个边界值,即n指定 boundary_value 提供的值的数目,但n不能超过999。所创建的分区数等于 1。不必按顺序列出各值。如果值未按顺序列出,则 Database Engine 将对这些边界值进行排序,创建分区函数并返回一个警告,说明未按顺序提供值。如果 n 包括任何重复的值,则数据库引擎将返回错误。 界值的取值一定是和分区依据列相关的,所以只能使用 CREATE TABLE 或 CREATE INDEX 语句中指定的一个分区列。
LEFT | RIGHT 指定boundary_value [ ,...n ] 的每个boundary_value属于每个边界值间的哪一侧(左侧还是右侧)。如果未指定,则默认值为 LEFT。
例如我们可以依据某个表的int列来创建分区函数: create partition function MyPF1(int) range left --默认是left,所以可以省略left
for values(500000,1000000,1500000)
如果换成range right,即创建分区函数时代码如下: for values(500000,1000000,1500000)
我们还可以根据日期列创建分区函数,例如: create partition function MyPF2(datetime)
很明显,这个分区函数创建了4个分区,因为此时n=3,所以分区总数是n+1=4。而那个int分区依据列 表明将要分区的那个表里面一定有一列是int类型,是分区依据列。这个分区函数我们用的是range left 个分区的取值范围如下表:
分区 取值范围 [负无穷,500000] [500001,1000000] [1000001,1500000] [1500001,正无穷]
如果换成range right,即创建分区函数的代码如下: Create partition function MyPF1(int) Range right
For values(500000,1000000,1500000) 哪么各分区的取值范围如下: 分区 取值范围 [负无穷,499999] [500000,999999] [1000000,1499999] [1500000,正无穷]
还可以根据日期列创建分区函数,例如: Create partition function MyPF1(datetime) Range right
For values(‘2008/01/01’,’2009/01/01’)
这个分区函数非常适合查询和归档某一年的数据。 分区 取值范围 1 [<=2007/12/31] 2 3
[2008/01/01,2008/12/31] [>=2009/01/01]
当然我们也可以根据月份分区,而分区依据列支持的数据类型非常多,参照项目的实际情况选择最合适分区的列类型。
分区方案
对表和索引进行分区的第二步是创建分区方案。分区方案定义了一个特定的分区函数将使用的物理存储结构(其实就是文件组),或者说是分区方案将分区函数生成的分区映射到我们定义的一组文件组。所以分 区方案解决的是Where的问题,即表的各个分区在哪里存储的问题。分区方案的创建语法如下:
CREATE PARTITION SCHEME partition_scheme_name AS PARTITION partition_function_name
[ ALL ] TO ( { file_group_name | [ PRIMARY ] } [ ,...n ] ) 分区方案语法的相关解释:
创建分区方案时,根据分区函数的参数,定义映射表分区的文件组。必须指定足够的文件组来容纳分区数。可以指定所有分区映射到不同文件组、某些分区映射到单个文件组或所有分区映射到单个文件 组。如果您希望在以后添加更多分区,还可以指定其他“未分配的”文件组。在这种情况下,SQL Server 用 NEXT USED 属性标记其中一个文件组。这意味着该文件组将包含下一个添加的分区。一个分区方案仅可 以使用一个分区函数。但是,一个分区函数可以参与多个分区方案。
partition_scheme_name 是分区方案的名称。分区方案名称在数据库中必须是唯一的,并且符合标识符规则。
partition_function_name 是使用当前分区方案的分区函数的名称。分区函数所创建的分区将映射到在分区方案中指定的文件组。partition_function_name 必须已经存在于数据库中。
ALL 指定所有分区都映射到在 file_group_name 中提供的同一个文件组,或映射到主文件组(如指定了 [PRIMARY])。如果指定了 ALL,则只能指定一个 file_group_name。
file_group_name | [ PRIMARY ] [ ,...n] 代表n个文件组,和分区函数中的各个分区对应。文件组必须已经存在于数据库中,如果指定了 [PRIMARY],则分区将存储于主文件组中。如果指定了 AL L,则只能指定一个 file_group_name。分区分配到文件组的顺序是从分区 1 开始,按文件组在 [,...n] 中列出的顺序进行分配。在 [,...n] 中,可以多次指定同一个文件组。如果 n 不足以拥有在分区函数中指定 的分区数,则 CREATE PARTITION SCHEME 将失败,并返回错误。
如果分区函数生成的分区数少于创建分区方案时提供的文件组数,则分区方案中第