sql2005的表分区问题(分区表性能和分区切换)解决方法

发布时间:2020-03-06编辑:脚本学堂
本文介绍下,sql server 2005中表分区的一些问题,比如分区表的性能,分区的切换等。有需要的朋友,参考下吧。

SQL Server 7 和 SQL Server 2000 支持分布式分区视图(distributed partitioned views,又称为物化视图,materialized views)。分布式分区视图由分布于多台服务器上的、具有相同表结构的表构成,而且还需要为每一个服务器增加链接服务器定义 (linked server definitions),最后在其中一台服务器上创建一个视图将每台服务器上返回的数据合并起来。这里的设计思想是数据库引擎可以利用多台服务器的处理能力来满足查询。

但是,分布式分区视图(DPV)受到很多限制,可以在SQL Server的在线帮助文档中阅读到。虽然DPV在一些情况下能够提供性能上的提高,但是这种技术不能被广泛的应用。已经被证明它们不能满足逐步增长的企业级应用的要求。何况,DPV的实现是一个费力的过程,需要DBA进行很多工作。

SQL Server 2005 开始支持表分区,这种技术允许所有的表分区都保存在同一台服务器上。每一个表分区都和在某个文件组(filegroup)中的单个文件关联。同样的一个文件/文件组可以容纳多个分区表。

在这种设计架构下,数据库引擎能够判定查询过程中应该访问哪个分区,而不用扫描整个表。如果查询需要的数据行分散在多个分区中,SQL Server 使用多个处理器对多个分区进行并行查询。可以为在创建表的时候就定义分区的索引。 对小索引的搜索(seek)或者扫描(scan)要比扫描整个表或者一张大表上的索引要快很多。因此,当对大表进行查询,表分区可以产生相当大的性能提升。

本篇文章不深入到分区的语法细节当中,这些可以在 SQL Server 2005 的在线帮助文档中找到。下面的例子基于存储着一个时间报表系统的数据的数据仓库。除了默认的文件组,我另外创建了 7 个文件组,每一个文件组仅包含一个文件,这个文件将存储由分区函数定义的一部分数据。

为了测试表分区的性能提升,我向这个分区表中插入了一千五百万行,同时向另外一个具有相同表结构、但是没有进行分区的表插入了同样的数据。对分区表执行的 INSERT 语句运行的更快一些。甚至在我的内存不到 1G 的笔记本电脑上,对分区表的 INSERT 语句比不分区的表的 INSERT 语句要快上三倍。当然,查询的执行时间依据硬件资源的差异而所有变化,但是还是能够在的环境中感到不同程度的提升。

我将检查更深入了一步,通过分别检查同一条返回所有行的、简单 SELECT 语句在分区表和非分区表上的执行计划,返回的数据范围通过 WHERE 语句来指定。同一条语句在这两个不同的表上有不同的执行计划。对于分区表的查询显示出一个嵌套的循环(nested loops)和索引的扫描。从本质上来说,SQL Server 将两个分区视为独立的表,因此使用一个嵌套循环将它们连接起来。对非分区的表的同一个查询则使用索引扫描来返回同样的列。当使用同样的分区策略创建多个表,同时在查询中连接这些表,那么性能上的提升会更加明显。

可以使用下面的查询来了解每一个分区中的行的个数:
 

select $PARTITION.TimeEntryDateRangePFN(time_entry_date) as Partition ,count(*) as [COUNT]   from fact_time_entry  group by $PARTITION.TimeEntryDateRangePFN(time_entry_date)  order by Partition

表分区对交易环境和数据仓库环境来说,都是一个重要的特征。数据仓库用户最主要的抱怨是移动事实表(fact table) 会花费太多时间。当装载数据到事实表的时候,用户查询(立方体处理查询)的性能会明显下降,甚至是完全无法成功。因此,装载大量的数据到事实表的时候常常需要停机。如果使用表分区,就不再出现这样的情况——确切的讲,一眨眼的工夫就可以移动事实表。为了演示这是如何生效的,我使用上面例子中相同的分区函数和表结构来创建一个新的表,这个表叫做 fact_time_entry2。表的主键从五千万开始,这样 fact_time_entry2 就不会包含表fact_time_entry中已经有的数据。

现在我把 2007 年的数据移动到这张 fact_time_entry2 中。同时让我们假设 fact_time_entry 表中包含着 2007 年之前的数据。在 fact_time_entry2 表完成数据的转移,我执行下面的语句:
 

alter table [fact_time_entry2] switch partition 8 to [fact_time_entry] partition 8

这条语句将编号为8的分区,这个分区恰好包含着2007年的数据,从 fact_time_entry2 移动到了 fact_time_entry 表中,在我的笔记本电脑上,这个过程只花费了 3 毫秒。在这短短的 3 毫秒中,我的事实表就增加了五百万条记录! 的确,我需要在交换分区之前,将数据移动到中间表,但是我的用户不需要担心——事实表随时都可以查询! 在这幕后,实际上没有数据移动——只是两张表的元数据发生了变化。

我可以使用类似的查询删除事实表中不在需要的数据。例如,假设我们决定我们不再关心2004年的记录。下面的语句可以将这些记录转移到我们创建的工作表中:
 

alter table [fact_time_entry] switch partition 2 to [fact_time_entry2] partition 2


这样的语句依旧在毫秒级内完成了。

现在,可以删除 fact_time_entry2 或者将它移到其他的服务器上。
事实表不会包含 2004 年的任何记录。这个分区还是需要在目的表中存在,而且它必须是空的。不能将分区转移到一个包含重复数据的表中。

注意:
源表和目的表的分区必须一致,同时被转移的数据必须在同一个文件组中。
即使受到这么多的限制,转换分区和无需停机就可以移动数据表的功能必将让数据仓库的实现变的前所未有的轻松。