在SQL Server中的关系型数据仓库分区策略
 

我们推荐本文的读者已经阅读并且理解以下的文章:

◆使用一个Microsoft SQL Server 2000数据仓库中的分区- http://msdn.microsoft.com/library/default.asp?URL=/library/techart/PartitionsInDW.htm
◆SQL Server 2000 步进的批量导入案例学习 - http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/incbulkload.mspx
◆Kimberly L. Tripp 所作的SQL Server 2005 分区表和索引 -
http://www.sqlskills.com/resources/Whitepapers/Partitioning%20in%20SQL%20Server%202005%20Beta%20II.htm

本白皮书关注的重点是关系型数据仓库和表分区。它的目标读者是:

◆通过使用Microsoft SQL Server中的分区视图实现了分区的开发人员和数据库管理员。这类读者将会得益于SQL Server 2005中的分区优势以及关于滑动窗口实现和策略的部份。
◆在未来计划使用分区的开发人员和数据库管理员将会通过详细阅读本白皮书而获益非浅。

数据库和系统管理员将会得益于有关存储域网络管理以及优化I/O利用策略的部份。

内容列表

对一个关系型数据仓库进行分区 
关于关系型数据仓库 
分区的好处 
在 SQL Server 7.0/2000中的分区技术 
在SQL Server 2005中的分区技术 
在SQL Server 2005中分区的优势 
标识一个查询计划中的 Demand Parallelism 
从SQL Server 2000的分区视图迁移到 SQL Server 2005 分区表/索引 

影响关系型数据仓库分区的因素 
数据量 
数据导入 
索引 
数据老化 
数据存档 
查询性能 

滑动窗口实现 
交换分区的最佳实践 
将数据存储到一个性价比高I/O子系统的技术 

关系型数据仓库的分区策略 
策略 I – 将一个分区绑定到它自己的文件组 
策略Strategy II – 将两个或更多分区绑定到同样的文件组 
哪个策略更好? 

结论 
附录 A: 性能数值 
批量插入性能 
转换性能 
索引构建性能 
数据库备份性能 
老化数据到ATA 磁盘 

附录 B: 平台列表 
Microsoft 软件 
服务器平台 
存储 
主机总线适配卡 
存储管理软件 

附录 C: 服务器体系结构 
附录 D: EMC CLARiiON 存储
 
拓朴 

附录 E: 存储隔离 
配置你的存储 

附录 F: 脚本 

对一个关系型数据仓库进行分区

以下的部份将会简要的解释关系型数据仓库的概念,为关系型数据仓库进行分区的好处,以及迁移到Microsoft® SQL Server™ 2005分区的好处。

关于关系型数据仓库

关系型数据仓库提供了一个广泛的数据来源以及一个用来构建业务智能(BI)解决方案的体系结构。另外,关系型数据仓库可以为报表应用程序以及复杂且专用的SQL查询所用。

一个典型的关系型数据仓库是由维度表以及事实表组成的。维度表通常会比事实表小一些并且其中提供了关于解释事实的属性的详细信息。一个维度的例子是货物,商店和时间。事实表提供了对商业记录的描述,比如在所有商店中货物销售的信息。事实表通过最近收集到的数据进行不断的更新。

一个成功的关系型数据仓库解决方案的实现包括细致而长期的规划。以下列出了在构建一个关系型数据仓库时要考虑的要素:

◆数据量
◆数据导入窗口
◆索引维护窗口
◆工作负载特征
◆数据老化策略
◆存档和备份策略
◆硬件特征

这个文档后面的部份将会有对以上要素的详细讨论。

一个关系型数据仓库在实现时可以采用分区的方法或者一个(巨大)事实表的方法。对于使用分区还是不分区方式的设计选择主要依赖于前面列出的各个要素。关系型数据仓库可以从数据分区中获益。以下部份着重谈到了分区为关系型数据仓库带来的好处。

#p#

分区的好处

当组织中的数据库向上扩展并且包含了大量的数据时,非常关键的是保持其高可用性并同时适应对小的数据库维护窗口的需要。这些需求使得分区成为对于超大型数据库而言的一个量身定制的技术。分区技术所强调的关键问题是——通过将非常大的表分解成相对较小的分区从而使诸如数据导入,老化以及存档等重要任务的管理更易于进行。Microsoft SQL Server通过在SQL Server 7.0/2000中的分区视图以及在SQL Server 2005中添加的对分区表的支持提供了分区技术。

在 SQL Server 7.0/2000中的分区技术

SQL Server 7.0通过分区视图引入了对分区技术的支持。在SQL Server 2000中,这一功能进行了增强支持了可更新的分区视图。当事实表可以被自然的分割或者根据数据范围划分成单独的表时,对于关系型数据仓库而言分区视图技术是再合适不过的了。分区视图的基表可以被UNION来表示成一个统一的数据集。分区视图大大降低成本应用程序的复杂性,原因是物理实现被从应用程序数据访问方式中抽象了出来。

在SQL Server 2000中,分区视图可以被扩展到包括分布式分区视图,从而启用跨多个服务器/实例的数据库联合。有关分布式分区视图的讨论超出了本文的范围。对此更详细的讨论,请参阅微软开发人员网络(MSDN)上的“分布式分区视图”,地址是:http://www.microsoft.com/sql/evaluation/features/distpart.asp!href(http://www.microsoft.com/sql/evaluation/features/distpart.asp.

在SQL Server 2005中的分区技术

在SQL Server 2005中通过使用表和索引的分区,可以降低在使用分区视图管理非常大的数据库时的复杂性。SQL Server 2005提供了用数据行作为最小的分区单位的水平范围分区功能。可以被分区的对象有:

◆基表
◆索引(聚簇和非聚簇的)
◆索引视图

范围分区是通过自定义的数据范围定义的表的分区。用户通过分界值,一个使用文件组映射的分区架构,以及映射到分区架构的表来定义分区函数。一个分区函数决定了一个表或索引中特定的一行所属于的分区。每个分区都是用一个通过一个分区架构映射到某个存储位置(文件组)的分区函数来定义的。对于在SQL Server 2005中实现分区的全面讨论,请参阅MSDN中的"SQL Server 2005 分区表和索引"。

以下部份阐述了SQL Server 2005中分区功能的优势并提供了将分区表迁移到SQL Server 2005的策略。

在SQL Server 2005中分区的优势

在SQL Server 2005中的表和索引的分区功能通过将其分解为更易管理的分区大大方便了对超大型数据库的管理。这一部份涉及了一些在针对关系型数据仓库的使用中分区表相对于分区视图的优势。

管理

一个使用分区视图的缺点是当你使用它的时候,数据库操作必须对单个的对象执行而不是对视图本身。举个例子,如果一个现存的索引必须被删除并且要创建一个新的索引,这些操作必须在每个相关的基表上执行。

在SQL Server 2005中,诸如索引维护这样的数据库操作是对分区表本身而不是底层的相关分区上进行的,因而在管理索引过程中大大减轻了负担。

更好的Parallelism机制

在SQL Server 2000中,操作是在单个表上执行的并且数据在一个分区视图的级别进行聚合。来自于基表中的行通过使用串联运算符进行汇集并显示视图。然后再在结果集数据上执行聚合。

在SQL Server 2005中,对分区表执行的查询使用了一个被称为demand parallelism的新的运算符。Demand parallelism受到系统资源和MAXDOP设置的影响。

使用分区表的查询将会比使用分区视图进行的同样查询更快的进行编译。当使用分区视图时查询的编译时间是与分区的数量成正比的,而使用分区表时查询的编译时间不会受到分区数量的影响。

在某些情况下,对分区视图进行查询可能会更好一些。以下描述了这样的情况:

◆当优化器选择使用demand parallelism时,parallelism的最小单位是一个分区。在SQL Server 2005中对一个分区表中的单个分区进行查询的性能可能不太好,原因是parallelism的级数被限制到了1。同样的查询如果对一个分区视图进行可能会好一些,原因是在一个分区内更好的parallelism
◆当分区的数量少于处理器的数量时使用分区视图会更好一些,原因是通过parallelism可以更好的使用处理器资源。当分区的数量大于处理器数量,而数据并不是在分区间平均分布时,对分区表查询的性能可能仍旧不太好
◆当分区中的数据分布不均时使用对分区视图的查询也会更好一些

标识一个查询计划中的 Demand Parallelism

下面是一个查询计划的示例,它是由一个加法聚合查询产生的。

划了红圈的部份标明了在查询计划中出现的demand parallelism。嵌套循环运算符左边的子demand parallelism是用分区ID来表示的。嵌套循环运算符右边的子demand parallelism是用分区表自身来表示的。在这张图表中,对于由左边的子demand parallelism所返回的每一个分区ID,一个并行的索引查找运算符对来自对应的分区中的行进行反复扫描。所有在嵌套循环运算符上进行的操作也受到由demand parallelism所建立的并行线程的数量的影响。左边的子demand parallelism表示了仅当分区剪切生效时,也就是当查询通过分区筛选结果时,被查询所影响的分区ID。

 

图表1:标识 demand parallelism

 

#p#

从SQL Server 2000的分区视图迁移到 SQL Server 2005 分区表/索引

一个现存的基于单个巨表或者分区视图的应用程序可以被重构或者迁移到一个基于分区的SQL Server 2005解决方案。要作出是重构还是迁移应用程序的决定,必须详细分析在性能,可管理性,以及可用性方面存在的需求。

一个将SQL Server 2000的分区视图迁移到SQL Server 2005分区表的简单路径将包括以下步骤:

◆创建一个分区函数和架构以确定每个分区的分界点和物理存储位置。分界点应当和分区视图的基表的差不多
◆在新建的分区架构上创建一个分区表。该表应当指定与分区视图的基表同样的物理结构,包括索引
◆将分区视图的每个基表交换为新建的分区事实表的一个分区。分区架构所关联的文件组必须与被交换进来的表所属的文件组相匹配。另外,要迁移的表必须符合交换提示的要求。举个例子,目标表不能是一个与架构绑定的视图的部件。关于交换提示的要求列表,请参阅SQL Server 2005联机丛书中的“使用分区交换有效的传递数据”

影响关系型数据仓库分区的因素

对于一个分区的关系型数据仓库的成功实现而言,包括了对数据库增长和易管理性的规划。接下来的部份阐述了影响关系型数据仓库分区的因素以及滑动窗口实现的详细信息。

数据量

当事实表的大小比较小时,分区只会添加更多的管理复杂性而不会带来更多的价值。事实表的大小是基于应用程序的特点并且由每一种实现方式所决定的。通常用户需要事实表在他们实施分区之前至少有100 GB。

数据导入

数据导入是一个数据仓库的核心部份。几乎所有的数据仓库都会周期性的处理最近收集的数据。是否成功的管理数据仓库取决于批量导入进程的效率以及导入过程中现有的数据能否继续使用。

在构建你的事实表时有两个选择:

◆建立一个巨大的表,或者
◆使用分区的方式

使用单个巨表这种方式与使用分区相比会导致较低的可用性,原因是在典型的关系型数据仓库环境中批量导入操作是步进执行的。例如,步进式的批量导入会从对目标表的锁定中获得巨大的好处。当使用单个表时,这样做就会阻止所有其它的用户在表导入的过程中访问它。对于步进导入数据的最佳工作方式是使用一个规划维护窗口。对于使用单个巨表这种方式中批量导入的全面讨论请参阅在http://www.microsoft.com/technet/prodtechnol/sql/2000/maintain/incbulkload.mspx 上的“SQL Server 2000步进批量导入案例学习”

分区方式让数据被批量导入到单个的分段表中,每一段都代表了一个确定的分区范围。分段表随后被添加到分区视图当中或者被当作一个新的分区交换到分区表中。由于每一个分区逻辑上都是由一个单独的分段表来代表的,因此步进的批量导入不会对任何针对现有数据的查询造成可用性和性能上的影响。

一个典型的数据仓库解决方案应当包括在批量导入数据的同时进行数据转换的功能。转换包括对源数据的清除和/或者聚合以产生目标库。

一个转换典型情况下是通过使用象微软系统集成服务这样的工具来完成的。如果过程中不需要一个复杂的工作流,用户可以选择使用SELECT/INTO来完成转换。
 
索引

在把数据导入到一个关系型数据仓库后,一般就要创建索引来为用户查询提供支持。在对关系型数据仓库体系结构造成影响的各个要素中创建和维护索引扮演了主要角色。

在没有索引时对事实表的查询性能通常比较差。对于使用单个巨大事实表的情况,一个最佳的解决方案是删除所有的索引,导入数据,然后重建索引。这种方法导致可用性的降低并且有一个不断增长的维护窗口,当表的大小增长到一定程度时这种方法可能就不太现实了。

在SQL Server 2000中当在基表上创建索引时,分区视图有效的处理了这个问题。SQL Server 2005支持在单独的分区上重建和重组索引,因而便于更好的管理分区索引。

数据老化

老化的数据被访问的频率比新的数据低一些。与日俱增的法律和规定需要业务保证老化的数据在线并能够被立即访问到。因而,在维护现有的数据的高可用性以及方便快速导入新的数据的同时有效的管理老化的数据对于一个企业是非常关键的。数据老化可以通过一个滑动窗口来有效的处理。如果数据被分区了,一个滑动窗口的实现就成为了可能。要查看更多的细节,请参阅本文后面的“滑动窗口实现”

数据存档

对于一个几T规模的数据仓库的成功实现并不以构建一个良好性能以及线性扩展的系统而结束。它也依赖于对一个高度可用的系统的维护。

如果数据被分区了,在SQL Server中的零散备份就可以实现。在SQL Server中的零散备份以及还原操作为分区的管理提供了更大的灵活性。零散备份备份意味着单个的分区,在被限制到它们自己的文件组时,可以被单独的备份和还原而不会影响整个数据库。在一个简单恢复模型中为了零散备份可以工作文件组必须设置为只读模式。在使用大容量日志恢复模型或者完全恢复模型的情况下,有必要备份事务日志-这样做主要是为了成功的还原文件组。关于这些限制的更多细节,请参阅在SQL Server 联机丛书中的“备份(Transact-SQL)”

查询性能

专用的查询是关系型数据仓库解决方案的一个主要部份。应用程序的特点以及查询所产生的结果的性质对于关系型数据仓库的分区有着极大的影响。例如,如果查询中有一个对应到分区键的筛选键,与对单个巨表进行的同样查询相比有更快的响应速度。这是因为对分区的使用促进了并行操作的使用并且在查询中的分区键意味着对数据的剪切更容易了。

#p#

滑动窗口实现

滑动窗口是影响对关系型数据仓库分区的一个关键要素之一因而值得用上一个单独的部份对其具体实现的细节进行讨论。

滑动窗口的场景包括将新的分区滑动进去以及将老化的分区从分区表或者视图滑动出来。当老化的数据存档时新的数据就可以用来让用户查询了。在滑动分区时的关键是最小化down机时间。

老化的数据可以被存档并且可以通过还原相应的备份在必要时取回,或者它也可以被移动到一个更低持久性,但更大I/O承受能力的始终可用以进行用户查询的子系统。

下面的图表展示了一个来自我们的测试场景的滑动窗口具体实现。在我们的测试场景中,从分布在全国的商店那里收集与消费者相关的销售数据。数据被导入,纯化,以及聚合来为商业决策提供支持。在我们的测试场景中,一个分区逻辑的代表了一周的有效数据。当前,八周的有效数据被标识为活动的。活动的数据比老化的数据的查询频率高很多。当有新的数据进来,老化的数据就会移出。这儿有一条业务规则表明老化的数据应当保持在线但是应当存储在一个经济有效的I/O子系统中。

 

图表2:滑动窗口方案

在SQL Server 2000中,滑动窗口可以使用分区视图来实现。缺点是分区视图必须被重新绑定来包括进在UNION视图中的新生成的数据。重新绑定需要一个元数据锁并且可能会被任何对现存视图或者基表的访问所阻塞。

通过对使用Transact-SQL语句将分区交换进和交换出的支持SQL Server 2005提供了一个对滑动窗口方案的更佳实现。交换分区需要在分区表上放置一个架构锁。当没有其它的进程在分区表上获取了一个表级别的锁时分区可以被交换进和交换出。如果分区被其它的进程使用或者如果其它的进程已经在分区表上获取了一个表级别的锁,交换分区的构建进程将会等待直到其它进程已经释放了锁。分区交换是一个对元数据的操作因而非常快速。

下面的步骤可以用来在SQL Server 2005中使用分区表实现一个滑动窗口方案:

◆创建分区函数,架构以及带有适当分界点和关联文件组的表。然后按照下面描述的四个步骤来执行初始导入
◆创建代表单个分区的表
◆分别地填充表
◆向表中添加约束检查来将数据值绑定到对应的范围上并且创建适当的索引。SQL Server 2005在创建分区表后创建初始索引时提供了一个额外的选项
◆将新近填充好的表交换进分区表的每一个分区
◆在初始导入之后,在一个表中任何新导入和交换进来的数据都不会成为分区表的一部份。一旦数据已经就绪,在设置好适当的分界点后表就可以被交换进分区表
◆类似的,老化数据可以被移动到更经济有效的I/O子系统但是仍然在线并保持可用状态

接下来的部份涉及了一些针对分割分区表以及将分区交换进分区表的最佳实践。

#p#

交换分区的最佳实践

只有当目标表或者分区是空的时滑动窗口方案才工作。例如,如果一个分区“P”属于分区表“PT”,它必须被交换出到表“T”,随后目标表“T”必须被清空。类似的,当将表“T”交换进分区表“PT”的分区“P”,目标分区“P”应当是空的。

当跨分区的数据移动被最小化时,滑动窗口方案工作最佳。下面的代码定义了分区函数和分区架构。当在这个分区架构上创建一个表时,分区表将会包括三个分区。第一个分区将会包含带有<=200401的键值的数据;第二个带有>200401 且 <=200403的键值;第三个带有>200403的键值。

CREATE PARTITION FUNCTION SALES_MONTHLY_PARTITION_FUNCTION (INT)
AS RANGE LEFT FOR VALUES ( 200401, 200403 )
GO
CREATE PARTITION SCHEME SALES_MONTHLY_PARTITION_SCHEME AS

PARTITION SALES_MONTHLY_PARTITION_FUNCTION ALL TO ([PRIMARY])
GO
CREATE TABLE t
(
 col1   INT
)ON SALES_MONTHLY_PARTITION_SCHEME(col1)
GO

当使用ALTER PARTITION函数的分割功能添加一个值为200402的新分界时,行会在相应的分区间移动。

ALTER PARTITION FUNCTION PARTITION_FUNCTION()
SPLIT RANGE (200402)
GO

通过在原始的位置删除行以及在新的位置添加行,行可以在分区间移动。和此次交换有关的分区在这一期间是不可访问的。在这个例子中,新建的第二个分区将会拥有在键值范围>200401 且 <=200402内的数据。带有对应键值的数据被从第二个分区中删除并且插入到新的分区。新的分区(>200401 且 <=200402)以及第三个分区(>200402 且 <=200403)在这一期间是无法访问的。

在我们的消费者场景中,新的数据是通过在活动的结尾处分割分区函数来添加的。老的数据是通过在老化的结尾处合并分区函数来删除的。这种实现滑动窗口的方式消除了在交换进和交换出分区时的跨分区的数据移动,也就是说,新的数据被批量的导入到一个表中并且随后通过在活动的结尾处分割它来交换进分区表,具体如下所示:

ALTER TABLE NEW_PARTITION SWITCH TO PARTITIONED_TABLE PARTITION

$partition.WEEK_PARTITION_FUNCTION (200404)
GO

对于更多的信息,请参阅在SQL Server联机丛书中的“设计分区来管理数据子集”

将数据存储到一个性价比高I/O子系统的技术

一个滑动窗口的具体实现可以通过将老化的数据滑动到一个性价比高的I/O子系统中来进行扩展。例如,在我们的测试场景中,我们将老化的数据从一个高性能的I/O子系统滑出到了一个没有同等高的性能但较为经济的I/O子系统中。特殊的滑动窗口实现可能无法通过在SQL Server中的备份与还原操作来完成。有一些替换的方式可以实现这样一个策略:

◆如果源文件是可用的,将数据导入到位于性价比高的I/O子系统的其它表中。重建索引。删除老的分区并且将新近导入的表添加到分区表中。无论你的数据集的大小,down机时间将会是交换分区所需要的时间,可以忽略不计。
◆如果导入的过程中包含了转换,在性价比高的I/O子系统上,通过使用一个SELECT/INTO查询从老化的分区提取数据来创建新表并重建索引应当更为有效。down机时间将会是交换分区所需要的时间。

关系型数据仓库的分区策略

接下来的部份阐述了对你的关系型数据仓库进行分区的两个主要策略。该部份将会讨论这些策略是如何作用于影响分区的要素的。

策略 I – 将一个分区绑定到它自己的文件组

一个分区可以使用以下的步骤被逻辑的绑定到一个文件组:

◆创建带有多个文件组的数据库,每一个文件组将会逻辑的对应一个分区
◆每个文件组中有一个文件。文件组可以包含一个或多个物理文件,并且这些文件可以在一个或多个逻辑卷/物理磁盘上创建
◆创建分区函数并将分界点映射到相应的文件组,使用分区架构来创建一个在文件组和分区之间的一一对应的关系

关于如何基于这个策略来实现分区的示例代码请参阅附录D

 

图表3:将分区映射到其自身的文件组

策略Strategy II – 将两个或更多分区绑定到同样的文件组

第二个策略是将一个或者多个分区映射到同样的文件组。文件组可以由一个(或者多个)分布在跨越一个(或者多个)逻辑卷/物理磁盘的物理文件来组成。对于基于这个策略实现分区的示例代码,请参阅附录D

 

图表4:将两个或更多的分区映射到同一个文件组

#p#

哪个策略更好?

分区可以通过使用这两个策略之一或者将两个策略有效的结合到一起来实现。关于策略 I 和 策略 II可以参考下面的表格,其中解释了这两个策略对影响关系型数据仓库分区因素的作用。

 

策略 I

策略 II

数据导入

·         SELECT/INTO SQL语句中不能明确的指定文件组。由于这一限制,在使用一个SELECT/INTO 语句时无法采用并行方式来完成初始转换

·         步进的数据导入不会被分区策略所影响

·         当所有的分区映射到同一个文件组时转换可以采用并行的方式完成

·         步进的数据导入不会被分区策略所影响

备份/还原

·         在文件组和分区之间创建一个一一对应的关系让在分区级别的零散备份和还原操作得以进行

·         在备份数据库之前确保分区被标记了只读状态。如果没有,当还原数据库时事务日志必须被前滚

·         如果所有的分区被映射到了同一个文件组,分区表作为一个整体可以使用单个的命令进行备份和还原

·         此策略在单个分区的粒度下不提供零散备份的灵活性

 

查询性能

·         如果文件组只包含一个文件,并且表会采用一个接一个的串行方式来进行填充,对这样的对象的扩展盘区的分配是连续的。这意味着SQL Server对于一个连续的扫描可以提供多达256 KB I/O (4个扩展盘区)速率

·         因为数据是连续的,因此对于大量的连续扫描可以提供更好的工作负荷

·         如果文件组是由多个文件组成的,SQL Server使用按比例填充机制,这样会导致扩展盘区出现碎片

·         类似的,在并行操作比如并行数据导入操作期间为对象/分区分配的扩展盘区无法保证是连续的

·         当为对象分配的扩展盘区不连续时,对于连续扫描SQL Server可以提供差不多64 KB I/O1个扩展盘区)速率

·         因为数据分布在许多的物理磁盘上,因此它有助于在进行大量的并发随机I/O操作时提供更好的工作负荷性能

作为一个替换的方案,可以在启动SQL Server时加上-E开关。当在启动时指定了-E开关时,SQL Server可以分配4个而不是1个扩展盘区。因而-E开关让SQL Server可以提供多达256 KB I/O速率,即使存在因使用了按比例填充机制而产生的扩展盘区碎片

结论

本白皮书讨论了影响分区的因素,以及对于设计分区可使用的两个主要策略的正反两面的对比。这里所提供的信息可能会对通过分区更有效的管理你的关系型数据仓库有所帮助。

有关的更多信息,请访问:http://www.microsoft.com/sql/

本文档展示了SQL Server 2005的一些与关系型数据仓库分区的相关特殊的功能。需要更多的信息,请参阅:

◆SQL Server 2005联机丛书提供了一些关于这个主题的有价值的信息,并且它可以作为使用SQL Server 2005实现数据分区的一个不错的起点。
◆CLARiiON CX600 Web站点: http://www.emc.com/products/systems/clariion_cx246.jsp

附录 A: 性能数值

所有在这一部份展示的数值都是在我们使用SQL Server 2005的测试过程中得到的。该测试是在附录B,C以及D中记录的硬件平台上进行的。

批量插入性能

在我们的测试中,我们可以在SQL Server 2005中使用刚刚超过一个小时的时间导入25亿行。事实表的架构中包含了九个整型列,一个日期类型列,以及一个字符型列。

在这里展示的性能数值是在所有的线程以并行的方式执行并且分区架构基于策略I的环境下捕捉的。

# 并行线程

执行时间

(在所有的线程执行时)

处理器使用率 (8个处理器)

# 行插入

批量拷贝吞吐量/

批量拷贝行/

磁盘吞吐量

8

52 分钟

88 %

2550835652

44.77 MB/

6,53,339

41.17 MB/ 8 LUNs on CLARiiON

在这里展示的性能数值是在所有的线程以并行的方式执行并且分区架构基于策略II的环境下捕捉的。

#并行线程

执行时间

(在所有的线程执行时)

处理器使用率 (8个处理器)

#行插入

批量拷贝吞吐量/

批量拷贝行/

磁盘吞吐量

8

52分钟

92.625%

2,550,835,652

46.42 MB/

677285

44.29 MB/ 8 LUNs on CLARiiON

为数据仓库分区所选择的策略并不影响批量导入的吞吐量。

#p#

转换性能

在我们的测试中,批量导入的过程后面跟着一个转换过程。转换过程包括将源数据和维度表联接在一起,其目的是为了使用提取的维度键值来填充目标仓库。下面是一段在我们的测试场景中使用的示例代码:

SELECT fact.fact_data_1,

sdim.store_key, pdim.product_key, tdim.time_key
INTO sales_transformed
FROM
 sales fact,
 stores sdim,
 products pdim,
 time tdim
WHERE fact.store_id = sdim.store_id
AND convert(bigint, (fact.system + fact.generation + fact.vendor + fact.product))

= pdim.productid
AND fact.weekid = tdim.weekid

转换查询是连续运行的,一个查询后面紧接着另一个,以致于在策略I中要保存前面的分区架构设置

# 并行线程

执行时间

处理器使用率

(1个处理器)

# 被转换的行

(每个转换)

磁盘读吞吐量

磁盘写吞吐量

1

每个转换差不多1小时13分钟

100%

差不多3亿行

 

3.5 MB/ 1 LUN on CLARiiON

(256 KB )

2.8 MB/ 1 LUN on CLARiiON (128 KB )

以下是来自一个分区架构的性能数值,它是基于策略II的并且所有的线程都是以并行方式执行的。

索引构建性能

在我们的测试中,我们可以用2个小时在跨越拥有25亿行数据的八个分区的三个整型列(维度键)上创建一个聚簇索引。其中的SORT_IN_TEMPDB选项允许tempdb数据库被用来对数据进行排序。在这个测试过程中使用这个选项来隔离在索引建立过程中用来读写的物理磁盘。当'sort_in_tempdb'选项设置为on时,tempdb数据库必须有足够的剩余空间在离线的索引创建过程中用来放置整个的索引。当排序在一个用户数据库中完成时,每个文件组/分区需要有足够的剩余空间来放置相应的分区。

在我们的消费者场景和设计中,每个分区逻辑的代表了一周的有效数据,这些数据带有一个和在任何给定的分区中所有的行相同的键值。对于每个单独的索引建立的parallelism的级数只能是1,因为distinct关键字值的数量是1。因而,在SQL Server 2005中我们在创建了分区表之后再创建起始索引的做法让起始索引的建立更好的利用了可用的处理器资源。

# 并行线程

执行时间

处理器使用率

#

8

2小时

86%

2,478,765,081

数据库备份性能

在我们的测试中,我们花了一个小时多一点的时间来备份活动分区到4个RAID 3 LUNs on EMC CLARiiON存储系统。活动分区分布在跨越8个LUN's的一个RAID 5 (4+1 10K RPM) EMC CLARiiON阵列上。目标设备是一个RAID 3 (4+1, 5K RPM ATA) CLARiiON阵列。

执行时间

# 备份的页 (8K)

备份/还原吞吐量/

1小时20分钟

30,518,330

50.15 MB/

老化数据到ATA 磁盘

老化数据到ATA磁盘包括使用SELECT/INTO语句批量导入数据。以下是一段用来实现滑动窗口的代码示例。

ALTER DATABASE [Customer] 
 ADD FILEGROUP [ARCHIVE_1]
GO
ALTER DATABASE [Customer] 
 ADD FILE (NAME = N'ARCHIVE_1', FILENAME = N'F:\ATA\RAID5\2\ARCHIVE_PARTITION_1.NDF',

SIZE = 100GB, FILEGROWTH = 0)
 TO FILEGROUP [ARCHIVE_1]
GO
ALTER DATABASE Customer MODIFY FILEGROUP [ARCHIVE_1] DEFAULT
GO
SELECT * INTO iri..Sales_129_ARCHIVE
 FROM VISF
 WHERE TIME_KEY = 129
 OPTION (MAXDOP 1)

一个等价于在现存的分区表上的聚簇索引的聚簇索引必须在新的表上创建,以便能够随后交换进分区表。在我们的测试中,我们使用了SELECT/INTO来滑出第一个有2.79亿行的老化分区到一个ATA磁盘阵列,整个过程用了不到20分钟。在同样的表上创建聚簇索引用了不到40分钟。

附录 B: 平台列表

以下的硬件和软件部件是用来进行本文中所描述的测试的:

Microsoft 软件
Microsoft Windows Server™ 2003 数据中心版 Build 3790
Microsoft SQL Server 2005 Beta 2

服务器平台
64-位 Unisys ES7000 Orion 130
16 Itanium 2 1.30 GHz CPUs 带有 3 MB 缓存
64 GB 内存

存储
EMC Symmetrix 5.5
- 96, 72 GB 10 KB RPM 磁盘 16 GB 读写缓存
EMC CLARiiON FC4700
- 155, 133.680 GB, 10 KB RPM磁盘16 GB读写缓存
- 30, 344 GB, 5 KB RPM磁盘(ATA)

主机总线适配卡
8 Emulex LP9002L 2 GB/秒光纤通道主机总线适配卡
所有的适配卡映射到CLARiiON 存储阵列,可以通过Powerpath 软件实现负载均衡

存储管理软件
EMC Powerpath v 3.0.5

#p#

附录 C: 服务器体系结构

我们使用了一台Unisys ES7000 Orion 130服务器来进行我们的测试。了解你的服务器的体系结构对于确定你的系统的理论上的吞吐量是要素之一。例如,一个100 Mhz PCI总线能够提供800 兆位/秒 的吞吐量。本附录简要的描述了ES7000 Orion的体系结构。

企业服务器ES7000 Orion 130是一个模块化机架固定式系统,它基于一个Intel芯片组以及Intel Itanium 2处理器家族。

在测试中使用的Orion服务器配置了2个服务器模块,16个处理器,以及64 GB内存。每个服务器模块带有一个IOHM(输入/输出集线器模块)。每个IOHM控制了一个由4个PCIAM's (PCI 适配器模块)所组成的I/O子系统。每个PCIAM有两个总线,每个提供2个PCI卡插槽。在每个总线上支持最高到100 Mhz的PCI卡。

那些高亮的槽是当前配置的。在总线BUS 0-0上的槽2以及在PCIAM 0-0/IOHM-0上的总线BUS 0-1是为本地的SCSI磁盘以及网卡配置的,一共给我们留了16个槽。其中的8个使用Powerpath软件映射到了CLARiiON存储阵列。

 

图表5:本场景中使用的CASSIN 服务器的I/O配置

附录 D: EMC CLARiiON 存储

我们使用了一个CLARiiON CX600存储阵列用来测试。本附录概况的描述了使用的存储阵列的配置信息。

CLARiiON存储阵列是由一系列的托盘和机架组成的。每个托盘可以放置多达15个磁盘。放在托盘中的大量磁盘被组织到一起来组成一个RAID组。从RAID组中生成的逻辑单元号码(LUN)可以在Microsoft Windows®操作系统中查看到。如果在将来需要添加更多的存储设备,磁盘可以被安装到存储托盘并且组成RAID组,新创建的RAID组可以和任何现存的RAID组联合在一起,形成一个可以在Windows操作系统中显现的Meta -LUN。Meta -LUN将会保持源LUN的LUN号。这些磁盘组成RAID组的形式不会影响性能,原因是CLARiiON存储阵列可以实现跨托盘和物理磁盘的负载均衡。

在我们的测试中使用的EMC CLARiiON存储阵列有着一个混合了RAID 1+0, RAID 5, 和 RAID 3的配置。RAID 1+0为数据库日志文件所用而RAID 5为数据库文件所用。RAID 3是用来备份和还原数据库分区的。10KB RPM 物理磁盘是 133 GB 的而 5KB RPM 磁盘是344 GB

我们的存储配置包括5个RAID 1 + 0 LUNs。LUNs是一个由8个物理磁盘组成的RAID组所生成的。由于磁盘使用了条带和镜像技术,因此每个LUNs都有大约500 GB ((8*133.680 GB)/2)的存储空间。RAID 1+0 LUNs中的两个被用来放置数据库的日志文件。

12个RAID 5 LUNs用来存储数据文件。5个RAID 5 LUNs是给tempdb数据库用的。这些LUNs中的每一个都有大约500 GB的存储空间。每个LUN源自一个RAID组。RAID 5的RAID组配置的相对于RAID 1 + 0的RAID组所包含的磁盘要少一些。RAID 5的RAID组是由5个133 GB磁盘组成的。

下面描绘的是在一个CLARiiON存储阵列中的RAID组和磁盘安排。来自于托盘2的3个物理磁盘和来自托盘1的两个物理磁盘组成了一个RAID组。下一个RAID组是通过交替来自每个托盘的磁盘的号来实现的。物理磁盘在托盘间交叉使用,作为一个最佳实践,是为了在托盘级别出现了任何的失败后系统仍可维持。

 

图表6:CLARiiON RAID 3/5 以及RAID组配置

拓朴

在我们的测试中,使用了光纤通道技术并实现了一个标准的光纤交换式拓朴结构。光纤通道是一个柔性的区域,在交换机级别使用了全世界通用的名称光纤主机总线适配器(HBAs)。在这个测试场景中LUNs都被盖了起来,只让主机服务器可以看到存储控制器。

图表7描述了在HBA和存储设备端口以及LUNs间的映射。由于在我们的测试场景中,逻辑卷直接映射到了单个的LUN,因此图表也可被看作是到逻辑卷的映射EMC's Powerpath(多路径软件)是用来在所有基于CLARiiON存储阵列的LUN间实现I/O负载均衡的。8个Emulex HBAs分成了区域来查看所有在CLARiiON存储阵列上的LUNS。有关安装Emulex HBAs with EMC storage的全部的详细信息,请访问: http://www.emulex.com/ts/docoem/framemc.htm!href(http://www.emulex.com/ts/docoem/framemc.htm.

 

图表7:HBA-存储端口-卷映射

#p#

附录 E: 存储隔离

在存储域网络环境中存储隔离扮演了一个重要的角色,特别是当数据在一个或者几个应用程序之间共享时。本附录着重谈到了在对你的关系型数据仓库进行分区时对存储隔离的一些需要考虑的事项。在这个附录中的例子沿用了在我们的测试一开始就使用的EMC Symmetrix存储阵列可以创建来自于多个物理磁盘的逻辑卷。类似的,多个逻辑卷也可以创建在同一个物理磁盘上。并且在某些情况下,多个逻辑卷可以在一组物理磁盘上创建。这种用法在存储域网络中是司空见惯的。在EMC Symmetrix中,物理磁盘被逻辑的分成了hyper卷。来自于多个物理磁盘的hyper卷可以成组创建一个Meta卷。Meta卷可以成组创建一个逻辑卷。在下面的图表中,数字1到32代表了单个的物理磁盘。每个物理磁盘被分成了8 个9-GB 的hyper卷。Hyper卷1.1 到8.1成组创建了一个Meta卷。Meta卷,在这张图中,是编号0001a, 0011a 到0071b的。Meta 卷 0001a 和0001b组成在一起创建了一个逻辑卷。在粗的竖线的右边的物理磁盘代表了镜像对。

 
 
图表8:Symmetrix 存储阵列磁盘配置逻辑图

例如,我们可以创建两个逻辑卷;一个,叫L1,是通过成组Meta 卷 0001a, 0001b来创建的。如果这些逻辑卷遇到了大量的并发I/O请求,磁盘系统颠簸将会发生,原因是hyper卷是从同样的一组底层物理磁盘那里创建的。为了避免在这种情况下发生的磁盘系统颠簸,需要格外小心的将可能会被并发访问的分区创建在隔离的逻辑卷和物理磁盘上。

在为任何数据仓库设计存储方案时,都存在着一个在物理级别的隔离数据和采用象将硬件资源满负荷使用的设计方案之间的平衡点活动分区以及存档分区的数据可以放置在同一个物理存储设备上,不过为了监视和管理的目的最好分别存储在单独的逻辑卷上——一个活动分区可以在逻辑卷L1上创建,而一个存档分区可以在逻辑卷L2上创建。尽管这两个分区在逻辑上是隔离的,但它们共享了同样的一套物理存储设备。

一个对应的替换的方法是将存档的数据和活动的数据在物理存储的级别就隔离开。这样就可以减少用于活动数据分区的存储设备的数量,不过由于数据的访问频率较低潜在的可能造成对为存档分区提供的存储设备的未充分利用。

现代的存储域网络设备装备了大量的缓存存储以及共享的不可预知的使用方式,最好是在实践时将数据分散到许多的存储设备。这样就最大化了资源的利用率以及依靠硬件提供的合格的性能。

配置你的存储

经过和EMC工程师们的共同工作后,基于我们的场景需要的存储阵列的配置得到了优化。在为一个SQL Server的具体实现配置存储时我们鼓励我们的用户同他们的硬件供应商紧密协作。

附录 F: 脚本

以下的脚本是在本白皮书前面被称为“关系型数据仓库分区策略”的部份中所描述的策略II实现过程中用来创建数据库,分区函数,以及分区架构的。

CREATE DATABASE [SALES]
ON PRIMARY
(
NAME = N'SALES_PRIMARY', FILENAME = N'D:\SALESPrimary\SALES_PRIMARY.MDF',

SIZE = 100MB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition1
(NAME = N'SALES_ACTIVE_PARTITION_1', FILENAME =

N'F:\RAID5\DATA\1\SALES_ACTIVE_PARTITION_1.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition2
(NAME = N'SALES_ACTIVE_PARTITION_2', FILENAME =

N'F:\RAID5\DATA\2\SALES_ACTIVE_PARTITION_2.NDF', SIZE = 100GB, FILEGROWTH = 0), 
FILEGROUP SALES_ActivePartition3
(NAME = N'SALES_ACTIVE_PARTITION_3', FILENAME =

N'F:\RAID5\DATA\3\SALES_ACTIVE_PARTITION_3.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition4
(NAME = N'SALES_ACTIVE_PARTITION_4', FILENAME =

N'F:\RAID5\DATA\4\SALES_ACTIVE_PARTITION_4.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition5
(NAME = N'SALES_ACTIVE_PARTITION_5', FILENAME =

N'F:\RAID5\DATA\5\SALES_ACTIVE_PARTITION_5.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition6
(NAME = N'SALES_ACTIVE_PARTITION_6', FILENAME =

N'F:\RAID5\DATA\6\SALES_ACTIVE_PARTITION_6.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition7
(NAME = N'SALES_ACTIVE_PARTITION_7', FILENAME =

N'F:\RAID5\DATA\7\SALES_ACTIVE_PARTITION_7.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition8
(NAME = N'SALES_ACTIVE_PARTITION_8', FILENAME =

N'F:\RAID5\DATA\8\SALES_ACTIVE_PARTITION_8.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition9
(NAME = N'SALES_ACTIVE_PARTITION_9', FILENAME =

N'F:\RAID5\DATA\9\SALES_ACTIVE_PARTITION_9.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition10
(NAME = N'SALES_ACTIVE_PARTITION_10', FILENAME =

N'F:\RAID5\DATA\10\SALES_ACTIVE_PARTITION_10.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_DIMENSIONS
(NAME = N'SALES_DIMENSIONS_1', FILENAME =

N'F:\RAID5\DATA\11\SALES_DIMENSIONS_1.NDF', SIZE = 450GB, FILEGROWTH = 0),
(NAME = N'SALES_DIMENSIONS_2', FILENAME =

N'F:\RAID5\DATA\12\SALES_DIMENSIONS_2.NDF', SIZE = 450GB, FILEGROWTH = 0)
LOG ON 
(NAME = N'SALES_LOG', FILENAME = N'F:\SQL\Path8\SALES_LOG.LDF',

SIZE = 120GB, FILEGROWTH = 0)
GO
CREATE PARTITION FUNCTION SALES_WEEK_PARTITION_FUNCTION (INT)
AS RANGE RIGHT FOR VALUES ( 129, 130, 131, 132, 133, 134, 135, 136 )
GO
CREATE PARTITION SCHEME SALES_WEEK_PARTITION_SCHEME AS

PARTITION SALES_WEEK_PARTITION_FUNCTION
 TO
(
SALES_ActivePartition1, SALES_ActivePartition2,

SALES_ActivePartition3, SALES_ActivePartition4, SALES_ActivePartition5,
SALES_ActivePartition6, SALES_ActivePartition7,

SALES_ActivePartition8, SALES_ActivePartition9, SALES_ActivePartition10
)
GO

以下的脚本是在本白皮书前面部份描述的策略II实现过程中用来创建数据库,分区函数,以及分区架构的。

CREATE DATABASE [SALES]
ON PRIMARY
        (NAME = N'SALES_PRIMARY', FILENAME = N'D:\SALESPrimary\SALES_PRIMARY.MDF',

SIZE = 100MB, FILEGROWTH = 0),
FILEGROUP SALES_ActivePartition
 (NAME = N'SALES_ACTIVE_PARTITION_1', FILENAME =

N'F:\SQL\Path2\1\SALES_ACTIVE_PARTITION_1.NDF', SIZE = 100GB, FILEGROWTH = 0),
 (NAME = N'SALES_ACTIVE_PARTITION_2', FILENAME =

N'F:\SQL\Path2\2\SALES_ACTIVE_PARTITION_2.NDF', SIZE = 100GB, FILEGROWTH = 0), 
 (NAME = N'SALES_ACTIVE_PARTITION_3', FILENAME =

N'F:\SQL\Path3\1\SALES_ACTIVE_PARTITION_3.NDF', SIZE = 100GB, FILEGROWTH = 0),
 (NAME = N'SALES_ACTIVE_PARTITION_4', FILENAME =

N'F:\SQL\Path3\2\SALES_ACTIVE_PARTITION_4.NDF', SIZE = 100GB, FILEGROWTH = 0),
 (NAME = N'SALES_ACTIVE_PARTITION_5', FILENAME =

N'F:\SQL\Path4\1\SALES_ACTIVE_PARTITION_5.NDF', SIZE = 100GB, FILEGROWTH = 0),
 (NAME = N'SALES_ACTIVE_PARTITION_6', FILENAME =

N'F:\SQL\Path4\2\SALES_ACTIVE_PARTITION_6.NDF', SIZE = 100GB, FILEGROWTH = 0),
 (NAME = N'SALES_ACTIVE_PARTITION_7', FILENAME =

N'F:\SQL\Path5\1\SALES_ACTIVE_PARTITION_7.NDF', SIZE = 100GB, FILEGROWTH = 0),
 (NAME = N'SALES_ACTIVE_PARTITION_8', FILENAME =

N'F:\SQL\Path6\1\SALES_ACTIVE_PARTITION_8.NDF', SIZE = 100GB, FILEGROWTH = 0),
FILEGROUP SALES_DIMENSIONS
 (NAME = N'SALES_DIMENSIONS_1', FILENAME =

N'F:\RAID5\DATA\11\SALES_DIMENSIONS_1.NDF', SIZE = 450GB, FILEGROWTH = 0),
 (NAME = N'SALES_DIMENSIONS_2', FILENAME =

N'F:\RAID5\DATA\12\SALES_DIMENSIONS_2.NDF', SIZE = 450GB, FILEGROWTH = 0),
LOG ON 
 (NAME = N'SALES_LOG', FILENAME =

N'F:\SQL\Path8\SALES_LOG.LDF', SIZE = 120GB, FILEGROWTH = 0)
GO
CREATE PARTITION FUNCTION SALES_WEEK_PARTITION_FUNCTION (INT)
AS RANGE RIGHT FOR VALUES ( 129, 130, 131, 132, 133, 134, 135, 136 )
GO
CREATE PARTITION SCHEME SALES_WEEK_PARTITION_SCHEME AS

PARTITION SALES_WEEK_PARTITION_FUNCTION
ALL TO (SALES_ActivePartition)
GO

(责任编辑 火凤凰 sunsj@51cto.com  QQ:34067741  TEL:(010)68476636-8007)