数据生命周期 - 分区

SQL Server 技术文章
技术评论员:Grant Dickinson、Dave Wickert、Len Wyatt 和 Stuart Ozer
适用于:SQL Server 2005

*
本页内容
简介简介
数据生命周期概述数据生命周期概述
关系分区关系分区
多维数据集分区多维数据集分区
ETL 更改ETL 更改
参考资料参考资料
结束语结束语

简介

成功的业务智能 (BI) 应用程序需要基于可靠的工具来运行,而有关如何成功地执行实现过程(简而言之,就是最佳实践信息)的相关知识库为它们提供了方便。Microsoft(R) 及其若干合作伙伴正通过 Project REAL 根据真实的客户情况来创建参考实现方案,从而找出 BI 应用程序基于 Microsoft SQL Server 2005 的最佳实践。这意味着将客户数据引入内部,并使用这些数据来解决各个客户在开发过程中将会面临的相同问题。这些问题包括:

架构的设计,包括关系架构和 Analysis Services 架构。

数据提取、转换和加载 (ETL) 过程的实现。

客户前端系统的设计与部署,以便进行报告和交互式分析。

生产系统大小的调整。

对运行中的系统的管理与维护,包括对数据的逐步更新。

通过分析真实的部署情况,我们可以全面了解如何使用这些工具。我们的目标是解决大公司在实际的部署过程中将会面临的所有问题。

本文对如何在关系数据仓库上和 Analysis Services 多维数据集中实现分区进行了详细介绍。除了给出有关做法的一般性概述之外,我们还给出了具体的代码段和课程,希望读者通过学习,能够从我们的成功经验与失败教训之中受益。我们希望任何基于 SQL Server 2005 设计或实现 BI 系统的人都能体会到参考实现方案的用处。

有关 Project REAL 的概述,请参见<指向白皮书“Project REAL – 技术概述”的链接>。在 Project REAL 持续过程中,将会引发大量的白皮书、工具和示例。要查找最新信息,请登录以下站点进行查对:

http://www.microsoft.com/sql/bi/ProjectREAL

Microsoft 及其在 BI 领域的多个合作伙伴共同致力于 Project REAL 的研究。这些合作伙伴包括:Apollo Data Technologies、EMC、Intellinet、Panorama、Proclarity、Scalability Experts 和 Unisys。Project REAL 所用的业务方案和源数据集由 Barnes and Noble 亲切提供。

注:此白皮书只是一份草稿。其中包含一些最佳实践建议,这是根据我们使用 SQL Server 2005 社区技术预览 (CTP) 的早期版本的经验得出的。此白皮书只在发行当日是准确无误的。本文中介绍的产品功能可能会有所更改,或者将来可能会得出更好做法信息。SQL Server 2005 仍是试用版,将来应该会有所更改。

数据生命周期概述

在任何数据仓库的实现过程中,开发适合于项目和业务需要的数据生命周期策略都是一项关键性的工作。数据生命周期涵盖项目的各个方面,但我们将其定义为仅包括处理新数据引入和推动旧数据删除的数据库管理过程。这样,就将数据生命周期合理地分成了三个方面:分区、将旧数据移到成本较低的磁盘上以及修剪维度。下面将对每个方面涵盖的内容进行简要说明。

分区

分区是将大型数据集分成更易于管理的较小块的一种方法。在本白皮书中,我们将专注于 SQL Server 表和 Analysis Services 度量值组的分区。我们将着重介绍水平分区,水平分区可根据分区列中的值将数据行分段。这在大型数据仓库的实现方案中是一种常用的策略,主要用作数据管理、多维数据集加载和维护的方法。这种方法对数据的查询也有好处,因为 SQL Server 和 Analysis Services 都提供了用来辨别哪些分区与查询相关的方法,即,假设查询使用分区列来筛选数据。

将旧数据移到成本较低的磁盘上

数据仓库的本质就在于它包含超大量的数据。任何可能的技术都可以并且应该用来管理维护这种大型数据集所需的资源成本。如果应用了某种日期分区策略,就可以查找按年代排列的分区,其中较早的数据不是急需的。这时,可以将相关数据移到仍可以查询但性能较差和/或不具有良好可用性的成本较低的磁盘上。这就需要根据业务进行权衡,以便在资源成本、查询性能和数据可用性之间取得平衡。

修剪维度

数据管理中有时会被忽视的一个方面是维度的修剪。这一问题经常比磁盘管理或数据库管理更重要。对于 Barnes and Noble 来说,最大的两个维度是项目(产品)维度和客户维度。当产品滞销、客户量逐渐减少时,业务用户不希望看到这两个维度,尤其是当他们浏览的维度具有数百万个成员时!

修剪维度的一个要求是不应有事实数据引用它们。Analysis Services 2005 目前提供了存储事实记录的“未知”维度键的功能,其中,一个或多个维度未在源数据中出现,但这在大多数情况下仍不够理想。如果存在事实记录,则它仅对匹配的维度记录有意义。

需要根据业务来决定何时可以从数据仓库中安全地删除维度(例如,“没有与该产品相关的销售和库存记录达到两年以后”),但从事实表中删除旧数据所遵循的策略也应该与此决定保持一致。

维度修剪的实现过程在另一个单独的白皮书中进行了详细介绍。

Barnes and Noble 当前的环境

2004年,Barnes and Noble 实现了一个使用 Microsoft 数据仓库框架的数据仓库。涵盖的方面包括客户的销售量、仓库库存量和 DC(分销中心)库存量。目前有三年的销售量、一年的仓库库存量和半年的 DC 库存量的数据。数据将每周加载到周表中。表命名标准已经制定,用于标识表中所包含的数据。目前,SQL Server 2005 Integrated Services (SSIS) 用于加载 SQL Server 2000 关系数据仓库,而 Analysis Services 2000 用于驻留少量多维数据集。全部关系数据仓库数据库的容量在 2 TB 左右。尽管数据只是进行概念性地分区,但这对于实现 SQL Server 2005 表分区还是有很多潜在的好处,我们将会在本文后面看到这一点。

在确定分区策略之前,需要了解一些要求。其中有些要求是关于如何加载数据以及如何基于给定的分区间隔来确定分区大小的。相应的业务指明了数据保持可用的时间。Barnes and Noble 的目标是最终获得连续五年的销售量历史记录和连续三年的库存量记录。由于他们还不具有那么多的历史记录,因此,为了演示“滑动窗口”实现方案的展开功能,我们建立了自己的一套对 REAL 项目的要求,本白皮书后面将对此进行介绍。接下来我们将评价 Barnes and Noble 进行分区的得与失,并在假定值得进行分区的前提下确定进行分区的最佳方法。

关系分区

关系分区是指基础关系数据存储的分区。在传统的数据仓库中,这种数据以维度格式存储,通常被称为星型架构或雪花型架构。我们的数据就是这样存储的。因此,表要么是维度表,要么是事实表。大多数维度表都相对较小,只有几列和几行。Barnes and Noble 具有两个非常大的维度表:项目维度表(7 百万行,5 GB 大小)和客户维度表(近 6 百万行,1 GB 大小)。第三大维度是存储维度,它只有 4000 多行,占用不到 2 MB 的磁盘空间。与事实表相比,客户维度和项目维度很小。

事实表行数占用的空间(数据和索引)加载的分区数

Tbl_Fact_Store_Sales

1,366,052,628

306 GB

157

Tbl_Fact_Store_Inventory

8,450,555,562

1037 GB

53

Tbl_Fact_DC_Inventory

51,387,065

4 GB

18

总计

1347 GB

为了使这些表在加载、备份/还原和索引维护方面易于管理,最佳解决方案是将他们在水平方向分为较小的表,这就是我们所说的“分区”方法。

分区的好处

分区的好处上面已间接提到。更明确地来说就是,将超大型表分区后,就可以在更低的级别上对其执行所有管理操作。对于已分区的表,可以将其表备份分段。SQL Server 2005 中的其他一些新增功能进一步为此提供了方便。即当文件组为只读文件组时,SQL Server 在文件组还原方案中将不再需要事务日志备份。在这种情况下,最新的分区可以独立于较早的稳定分区而驻留在文件组上。可以单独将稳定分区放在它们自己的只读文件组上,这些稳定分区只需进行一次维护和备份。这样一来,就只有不稳定分区需要维护。在已分区的情况中,其他操作(例如索引维护)也将变得更加容易。这就是有效管理一个几 TB 的数据库与管理一个不到 100 GB 的数据分区之间的差别。

另一个好处是查询性能方面,尤其是在数据仓库环境中。无论是由 Analysis Services 在多维数据集处理过程中发出查询还是在最终用户直接查询关系数据仓库时,都是这样。处理多维数据集时,如果使用与关系源相同的分区列将目标多维数据集分区,性能将得到改善。如果对已分区的多维数据集进行处理,Analysis Services 将发出一个查询,以限制包含在分区内的数据。例如,如果目标分区包括于 2005 年 1 月 1 日结束的那一周的相应数据,Analysis Services 将向 SQL Server 发出一个查询,要求仅在那一周内的数据。这大大减少了要扫描的分区数。

客户针对关系数据仓库直接发出的查询通常具有一个日期组件。一般的查询是在当前时期与去年同期之间进行销售量的比较。在此类情况下,SQL Server 经常会限制要引用的数据量,从而改善查询性能。针对 Analysis Services 的查询也是如此。

SQL Server 2000 中的选项

SQL Server 2000 中有一个分区选项,即“分区视图”。要创建分区视图,只需定义一个视图,在其中列出所有参与该视图的表,并使用“UNION ALL”语句将这些表连接起来。为了使查询优化器能够隔离出与给定查询相关的分区,必须具备一个受信任的约束来报告哪些分区包含哪些数据。“受信任的”约束是指用“WITH CHEK”选项创建的约束。如果创建约束时未使用此选项,或者每次加载时在未出现 CHECK_CONSTRAINTS 提示的情况下就将数据批量加载/备份到表中,则与约束冲突的表中可能会存在数据。SQL Server 将不信任这些约束,因此这些约束在优化和功能上的许多好处将无法实现。

SQL Server 2005 中的选项

SQL Server 2005 为分区提供了一个新增选项 - 分区表和索引。分区表提供了一种对表的其他用户影响最小的加载和管理水平数据段的方法。其他论坛中包括有关分区表的详细介绍,因此本文只扼要重述一些高级概念,而不再重复其他相关内容。本文结尾列出了有关其他信息的参考资料。

表分区允许将表或索引的每个逻辑独立段作为单独的实体来处理。这些段或分区可以从表的外部加载,以便在整个加载过程中,加载不会影响到分区表的用户。完成对分区的加载后,该分区将被“切换入”分区表中。成功进行分区切换必须具备几个条件,其中最常见的是:

分区表结构的构架必须与要切换入的表相同。这包括列名、数据类型、为空性属性、排列规则、精度和主键约束

对分区表创建的任何索引必须对要切换到的表同样创建,并且除名称外的所有索引属性都必须匹配(例如,索引列、群集属性和唯一属性)。

目标分区必须为空。

源表和目标分区必须在同一个文件组上。

源表必须定义了一个与目标分区兼容的受信任的检查约束。

要重申的是,这里只列出了部分要求。可以在 SQL Server 联机丛书中找到其他更具体的限制。

本文包含许多关于 SQL Server 如何实现分区表的特定术语。这些术语的详细信息包含在其他资源(例如 SQL Server 联机丛书和 Kimberly Tripp 的关于分区表的白皮书)中(请参见本白皮书结尾的参考资料),但可以简短地定义如下:

分区函数

分区函数是一种物理数据库对象,用于定义分区的上边界或下边界。

分区方案

分区方案是基于分区函数的一种物理数据库对象。分区方案定义了由分区函数定义的每个分区在磁盘上的位置。

对齐

如果分区表和索引基于同一个分区函数(无论隐式还是显式),则它们被称为是对齐的。

并行定位

如果分区表和索引共享同一个分区函数(它们是对齐的)和同一个分区方案,则它们被称为是并行定位的。这样一来,它们的分区边界就是相同的,符合这些边界的数据位于同一个文件组。

RANGE LEFT/RANGE RIGHT

这可能是关于表分区的一个比较难懂的方面。分区函数用 RANGE LEFT 或 RANGE RIGHT 来定义。它们之间的区别是:用 RANGE LEFT 定义的函数意味着符合边界的分区数据位于边界的左侧;用 RANGE RIGHT 定义的函数意味着符合边界的分区数据位于边界的右侧。因此,如果边界为“01/01/2005”并且分区函数规定 RANGE LEFT,则“01/01/2005”就是上边界,符合边界的数据位于边界的左侧,小于该边界。

MERGE

对分区进行合并可使两个分区变为一个分区。MERGE 用于删除分区。

SPLIT

对分区进行拆分可使一个分区变为两个分区。SPLIT 用于添加分区。

比较分区表和分区视图

分区视图在 SQL Server 2005 中仍然可用,仍可以作为在数据仓库中进行分区时的一项较好的选择。大多数情况下,分区表将更易于管理。下表概要列出了两种方法的优、缺点:

表 1:SQL Server 2005 分区表与分区视图

功能分区表分区视图

表的维护

表作为单个实体来管理。

每个参与的表各自都是一个实体,必须对其进行元数据更改。

索引

每个分区必须具有相同的索引。

每个表可以具有各自的索引策略。

实现

两者在实现的复杂程度方面大致相同。发生问题时,分区表会更明确地引发错误。

可能会存在隐蔽的问题使分区视图无法按预期进行操作。一个常见问题是创建检查约束而没有检查当前值。分区视图能够成功实现,但由于不明原因而不能正确进行优化。

编译时间

由于所有分区的索引方式都一样,因此优化器可以对每个分区使用相同的执行计划,从而使编译时间大大缩短。

由于分区可以具有不同的索引,因此优化器必须针对每个表(分区)来估计最佳执行计划。当分区视图中存在很多表时,编译时间将会很长。

加载

可以从外部加载分区,从而将对表当前用户的影响降至最低。

可以从外部加载表,从而将对视图当前用户的影响降至最低。

切换入新数据

是一种快捷的元数据操作,将自然进行排队。

是一种元数据操作,但是 ALTER VIEW 语句会无限期地等待 SCHEMA 锁。

可更新性

除了创建分区表所需的规则以外,不必遵守其他特殊规则来使该表可更新。分区表可以具有标识列,不需要主键等。

存在一些使得分区视图难以具备可更新性的限制,例如参与的表没有标识列并且存在主键。这通常意味着必须直接更新基础表,这样就使得 INSERT 和 UPDATE 的编码复杂化。

备份/还原

可以单独或一起备份/还原表的分区,具体取决于文件组的实现方案。

注: 除非文件组被标记为只读,否则还原文件组需要从备份点开始重新应用事务日志。

可以单独或一起备份/还原构成分区视图的各个表,具体取决于文件组的实现方案。

分区视图表还可以驻留在单独的数据库中,这样就可以对单独的分区进行单独的数据库备份。

注:除非文件组被标记为只读,否则还原文件组需要从备份点开始重新应用事务日志。

数据库内容

一个分区表中的所有分区必须驻留在同一个数据库中。

参与分区视图的各个表可以驻留在不同的数据库中。这就使得对历史记录段的备份和还原操作非常容易实现。

查询并行处理

在并行查询计划中,各个分区是并行处理的单元。如果查询仅涉及单个分区,将不通过并行处理访问该表。

将单独考察分区视图中的每个表,以确定是否进行并行查询访问。如果查询仅涉及单个表,则可以通过并行处理访问该表。

批量加载

分区表可以直接作为批量插入/备份操作的目标。

分区视图不能作为批量插入/备份操作的目标 – 目标必须是视图中的各个表。

实现决策

Barnes and Noble 在 SQL Server 2000 中没有实现分区视图,这是因为编译时间太长,通常在 30 秒左右。目前有三年的销售量数据,涉及 156 个表分区。跨越整个分区视图的查询需要检查每个基础表来估计执行计划。这会使分区视图不可用。除编译时间这一原因外,选择分区表而不是分区视图的最有说服力的原因是易于对表进行维护,以及易于执行跨越多个分区的 INSERT、UPDATE 和 DELETE 操作。

选择了分区方法之后,接下来我们需要确定分区列和最佳数据间隔。如果分区列为日期列,将会获得在数据仓库中进行分区带来的很多好处。在我们的例子中,分区列从字面上看不是 datatime 数据类型,但该列中包含的数据指的是存储为整数 (CCYYMMDD) 的日期。

分区设计决策

第一个设计决策是确定分区键。销售量事实表中有一个 Transact_Date 列,其数据类型为 SQL Server datetime。这初看起来好像是理想的分区列。但此列未定义在任何一个库存量事实表中。“日期”列其实是以 SQL Server int 数据类型(格式为 CCYYMMDD)的形式实现的,以便减少占用的空间。此列名为 SK_Date_ID,在全部三个事实表中都是一致的,因此被选作分区键。选择此列引发的一个结果是它将试图按 Transact_Date 列查询销售量事实表,这是因为该列的数据类型才真正为 datatime。请记住,只有当查询对分区列进行筛选时,查询优化器才能限制完成查询要扫描的分区。

下一个设计决策是确定分区间隔。由于是在逻辑上按周执行库存量加载(在每周开始时创建一个快照并每日更新它),因此 Barnes and Noble 的数据目前以周表的形式存在。这也使每个分区的大小保持在 25 GB 左右,以便易于管理。月分区方案将约为 100 GB,这比较难管理。我们对销售量表选择了同一分区策略,以便获得分区表对齐带来的好处,这将在下文进行介绍。

或许我们应当考虑最多的是分区在磁盘上的布局方式。我们是否要用一个或多个文件将分区映射到一个或多个文件组上?白皮书“Strategies for Partitioning Relational Data Warehouses in Microsoft SQL Server”中对两种高级分区映射策略的优、缺点进行了详细介绍(请参见本文结尾的参考资料)。我们认为最好将每个分区分别映射到各自的文件组,其中每个文件组有一个基础文件。这样我们就能控制该分区在磁盘上的布局方式了。关于这样做是否理想存在各种不同的观点。可以说,使用单独的文件组强制执行的分区是通过磁盘子系统来实现的。使用单独文件组实现方案的原因主要有三个:

1.

可以在文件组级别设置只读属性。分区 8 周后,即不再插入事实表时,我们就可以打开该只读属性以便逐一启用备份/还原方案(这是 SQL Server 2005 中的一个新增功能)并减少锁定时间。

2.

可以在磁盘级别执行旧方案。要实现这种可能性,各个分区必须分别位于各自的磁盘文件中。如果跨越几个磁盘的多个分区位于一个文件组中,就不可能实现此目的。

3.

为了实现将较早的分区移到成本较低的磁盘的时效,需要至少两个文件组,一个用于活动磁盘阵列,另一个用于非活动磁盘阵列。这可以防止将全部内容都映射到单个文件组上。

对 Barnes and Noble 环境实现分区表包括两个方面的内容。首先,我们必须将现有的所有表移到创建的分区表中,然后需要修改现有的 ETL 过程,以便每周创建新的分区并向这些分区中加载新的数据。下文将单独对此进行介绍。

分区索引?

关于索引分区只需做出几项决策。首先应确定是否一定在分区表上对索引进行分区。如果是,则需要确定索引是否应该与基表对齐。最后,需要确定是否将它们与基表并行定位。做出分区索引决策是比较容易的。分区的整体策略首先是与可管理性和易管理性密切相关的。由于只有一小部分数据是不稳定的,因此如果大型索引中的大部分内容无需更改,则管理整个索引是没有意义的。由于大多数索引维护可识别分区,因此可以对部分索引而非整个索引执行必要的维护。

除了群集索引以外,其他索引的实际分区方式可以与基础表的分区方式不同。但这在进行定期数据换入和换出的情况下没什么意义。如果索引与数据遵循同一个分区函数,则由于数据以同样的方式分段,所以能更高效地移入和移出。

最后一个问题是关于索引将驻留的位置的。默认情况下,群集索引遵循基表的分区方案,该方案定义了分区在磁盘上的驻留位置。非群集索引可能是对一个单独的分区方案创建的,但是如果能保证相关数据位于同一个文件组中,SQL Server 就可以更容易地进行并行操作。有关更多信息,请参见 Kimberly Tripp 关于“在 SQL Server 2005 中进行分区”的白皮书。

现有表到分区表的转换

转换现有表的第一步是回顾 Barnes and Noble 当前的环境。维度表和事实表当前存储在两个数据库中,一个数据库用于存储库存量事实表(仓库与分销中心的库存量),另一个用于存储销售量事实表和维度表。对于 Project REAL,这两个数据库在数据屏蔽过程中合并为了一个数据库,即 REAL_Warehouse。为使我们的分区练习更具有针对性,我们只处理事实表。

原有的销售量事实表用 SQL Server 物理周表来表示。每个表都按照命名约定“Tbl_Fact_Store_Sales_WE_ccyy_mm_dd”命名,其中的日期是指每周结束(星期六)的日期。表“Tbl_Fact_Store_Sales_WE_2003_12_27”可以作为一个示例,它包含从 2003 年 12 月 21 日至 2003 年 12 月 27 日的数据。

库存量事实表的相关信息与上述类似。库存量事实表实际有两种形式,一种用作 DC(分销中心)库存量事实表,另一种用作仓库库存量事实表。这两种表的命名约定分别为“Tbl_Fact_DC_Inventory_WE_ccyy_mm_dd”和“Tbl_Fact_Store_Inventory_WE_ccyy_mm_dd”。由于这两种表的元数据大不相同,因此无法将它们合并在一起。与销售量表一样,分区列为具有相同的数据类型的 SK_Date_ID 列。

由于数据类型一致,因此我们可以在 3 个事实表中选择一个共同的分区列 SK_Date_ID。这使得我们可以对齐这些表以便于连接。分区键是一个代表日期的整数。例如,“2004 年 12 月 25 日”表示为 20041225。由于现有的物理源表逐周增长,因此极大地方便了向类似分区的转换。分区表中的一个分区等同于一个物理源表。以下是加载每个逻辑事实表所需步骤的高级表示方式:

创建所有文件和文件组

创建分区函数,这将定义出给定分区表的所有边界。以下是 CREATE PARTITION FUNCTION 语句的一部分:

CREATE PARTITION FUNCTION pf_Range_Fact(int)
AS 
RANGE LEFT FOR VALUES (
   20020105,
   20020112,
   20020119,
   .
.
.
   20041231)

创建分区方案,这将定义每个分区在磁盘上的布局方式。我们决定对齐库存量事实表和销售量事实表,但它们不是存储对齐的。这将便于连接独立的分区,但是会将 I/O 操作在物理存储器之间分散开。我们所谓的“对齐”是指多个分区表的分区函数是等效的。这并不意味着分区函数必须真正相同,而是指边界定义、分区键数据类型和分区数必须一致。存储对齐是指两个表上的同一给定分区驻留在同一个文件组中。

创建分区表,这看起来好像与其他任一 CREATE TABLE 语句相同,但它指定的是创建基于上述分区方案的表。

对于每个源表,例如 dbo.Tbl_Store_Inventory_WE_2004_12_25:

使用 SELECT INTO 语句选择要切换到分区表的临时表。

使用 WITH CHECK 语句添加一个与目标分区相对应的检查约束。

使用 $partition function:SELECT @PartitionNum = $partition.FactRangePFN(20041225) 确定目标分区

使用 SWITCH 语句将临时表切换到目标分区

创建索引

注:如果原有的销售量和/或库存量表被移到同一数据库中已驻留在目标文件组的一个分区表中,我们就可以跳过 SELECT INTO 步骤,而只需在创建检查约束并将分区列为改为 NOT NULL 后将这些表切换到相应的分区。但事实并非如此,因此我们需要先将源表复制到驻留在目标文件组的一个单独的表中,然后再将源表切换到分区表。

CREATE PARTITION FUNCTION 和 CREATE PARTITION SCHEME 命令是自动生成的。如果手动键入这些命令,特别是每周都要键入的情况下,将会非常枯燥而且容易出错。自动生成这些命令还使得我们能够灵活地定义分区边界,并且更容易确保得出与分区函数边界匹配的分区方案。包含此代码是为了供 Project REAL 项目重用。

最初创建分区表的过程将会是一个极其漫长的过程。在我们的示例中,我们真正复制了 1.5 TB 数据。我们的挑战在于怎样使此过程尽可能快速。由于记录和锁定开销过大,因此可以迅速排除 INSERT INTO 方法。BCP 方法需要首先将数据复制到其他磁盘,然后使用 BULK INSERT 语句批量插入回临时表。与 SELECT INTO 方法相比,这使我们可以更好地控制文件的复制方式,但实际上执行 SELECT INTO 语句比单单用 BCP 操作备份数据快。SELECT INTO 方法经证明比 BCP/BULK INSERT 组合方法快 9 倍以上(即使在确认 BCP 不进行记录且将锁定时间最小化之后)。

SELECT INTO 方法存在的主要问题是无法指定在该过程中创建的表所在的文件组。这一问题非常严重,因为此临时表的文件组必须与其目标分区的文件组一致。为确保正确定义临时表的文件组,就在执行 SELECT INTO 之前,我们更改了数据库的默认文件组,以确保该表创建在目标文件组中。这极大地限制了我们并行处理表的能力,这是因为所有并发的 SELECT INTO 语句都必须使用同一个文件组(一次只能使用一个默认数据库文件组)。这还将引入一个磁盘热点,可能会对并行处理产生负面影响。SELECT INTO 方法的序列化性质也比 BCP/BULK INSERT 方法更理想,因此我们选择了前者。

源表中没有对其中含的日期数据创建约束。与目标分区边界一致的源分区列上必须存在受信任的检查约束才能成功进行切换。此约束是在 SELECT INTO 语句完成后的加载过程中添加的。

此外,在全部三个表上,分区列 SK_Date_ID 都被定义为可以为空。尽管我们可能已在分区函数中定义了边界,即,分区函数定义了含有 SK_Date_ID = NULL 的所有行应属于的分区,但是如果分区策略是基于日期的,则此定义将不起作用。此外,SK_Date_ID 为 NULL 也会违反 CHECK CONSTRAINT。我们已向 Barnes and Noble 确认 SK_Date_ID 绝对不会为空,因此对整个架构实施了此业务规则。

以下是一个比较大的库存量事实表的细目分类:

表 2:复制表分区细目分类

步骤经过的时间 (mm:ss)占总时间的百分比

SELECT INTO

7:33

74%

ALTER SK_Date_ID 非空

5:51

ALTER ADD 检查约束

2:42

26%

SWITCH(切换到分区表)

0:00

0%

总计

10:15

请注意,我们没有使用 ALTER TABLE 语句对目标表中的 SK_Date_ID 列实施 NOT NULL 约束。我们可以改为在执行 SELECT INTO 语句的过程中通过使用 ISNULL 函数来实施该约束。要演示这一点,请参见以下语句。

SELECT <Column 1>, 
<Column 2>, 
isnull([SK_Date_ID], -1) as [SK_Date_ID],
.
.
.
<Column x>
INTO dbo.Tmp_NewPartition FROM Tbl_Fact_Store_Sales_WE_2005_01_01

在实施此“技巧”之前,用于添加 NOT NULL 约束的 ALTER TABLE 语句需要对每个表花费大约 6 分钟的时间;如果对三个分区表中的每个分区都应用此技巧,将节约大量的时间。仅对于仓库库存量事实表,使用此“技巧”节约的时间预计达 5 个小时以上!

检查分区表

加载新的分区表之后,我们首先会想到要看一下结果。但我们会迅速发现没有什么是可以一目了然的。最初不会看到任何结果,这是分区表不同于非分区表之处。可喜的是,数据库中的对象大大减少了。源数据库包含 229 个事实表,而使用分区表的数据库仅包含 3 个事实表。通过查看 SQL Server Management Studio 中的属性可以进一步仔细检查这 3 个事实表中的任何一个。下图展现了 Tbl_Fact_Store_Inventory 表的属性:

图 1

图 1:分区表的属性
查看实际尺寸图像

通过行数可以明显看出加载是成功的。可以另外进行检验来验证源表的总行数等于此对话框中指明的行数。“Storage”区显示表已被分区,并指明了分区所映射到的分区方案。

可以查询动态管理视图 (DMV) 来了解对所有分区中的行的分布情况的详细指示。此操作的开销会比较大,因为要对表中的每个分区都进行实际计算,但使用以下查询可以看到分区表和行分布情况的整体详细视图。

SELECT $partition.pf_Range_Fact(o.SK_Date_ID) AS [Partition Number]
      , min(o.SK_Date_ID) AS [Min Date]
      , max(o.SK_Date_ID) AS [Max Date]
      , count(*) AS [Rows In Partition]
FROM dbo.Tbl_Fact_Store_Sales AS o
GROUP BY $partition.pf_Range_Fact(o.SK_Date_ID)
ORDER BY [Partition Number]

它将生成有关销售量事实表的以下信息(简短起见只包括了结果集的一部分)。

分区号最小日期键最大日期键分区中的行数

140

20040829

20040904

8061536

141

20040905

20040911

8308355

142

20040912

20040918

8044390

143

20040919

20040925

7824844

144

20040926

20041002

7864007

145

20041003

20041009

7853734

146

20041010

20041016

8056497

147

20041017

20041023

8017784

148

20041024

20041030

7684242

149

20041031

20041106

7924918

150

20041107

20041113

8845731

151

20041114

20041120

8963072

152

20041121

20041127

9361857

153

20041128

20041204

11201851

154

20041205

20041211

13974601

155

20041212

20041218

17549392

156

20041219

20041225

18736647

157

20041226

20041231

12016107

增量处理

一旦生成了分区表,我们就需要进行维护以使它们能够正常运行。这包括在每周开始为每个分区表创建一个新分区。除此之外,我们还选择了实现“滑动窗口”,并将旧数据从可用空间较少的磁盘迁移到成本较低的磁盘上。

滑动窗口

“滑动窗口”的实现方案修改了分区表中可用数据的范围,即随着时间的推移,如果引入了新数据,则添加新的分区;如果不再需要历史数据,则删除旧的分区。分区表中可用的数据量只取决于业务要求,不同实现方案的业务要求各不相同。业务要求可以规定连续 3 年的销售量数据始终可用。在这种情况下,在添加新的销售量数据的同时可以淘汰旧的销售量数据。为了阐明滑动窗口的实现过程并提供一个关于如何对 SQL Server 2005 分区表添加和删除分区的示例,我们概述了以下应用场景:

1.

向一个新的外部事实表中加载关于在 2005 年 1 月 1 日结束的那一周的某些信息之后,我们希望使这些新信息在分区表中可用。

2.

首先,我们“拆分”分区函数中的最后一个分区(按照定义,它应包含 2004 年 12 月 25 日之后的所有信息)以定义一个新边界,从而包含 2004 年 12 月 25 日到 2005 年 1 月 1 日之间的所有信息。

3.

现在让我们将新创建的分区(该分区是空白的)与在开始步骤 1 之前加载的外部表进行切换。这会产生一个空白的外部表,我们将删除该表。

4.

现在,我们拥有了一个包含新数据的分区表。

5.

接下来,我们要删除最早的一个分区中的数据。首先,用与分区表(包括索引)相同的表架构创建一个空白外部表。

6.

我们将分区表的第一个分区与刚创建的外部表进行切换。

7.

现在我们将第一个分区(它包括 2002 年 5 月 1 日之前和当天的所有日期)与第二个分区合并在一起。现在,第一个分区就包括 2002 年 12 月 1 日之前和当天的所有日期。由于在 2002 年 5 月 1 日结束的那一周的相关数据不在分区表中,因此我们可以将该表在某个位置存档,然后从 SQL Server 中删除该表。

滑动窗口的实现过程通常表现为通过拆分/切换和合并/切换操作同时添加和删除分区。但是,添加和删除分区的操作并非直接相关,它们肯定可以单独发生。滑动窗口的变体形式可能会指定不能以添加新数据的频率来删除旧数据。要求具备 3 个完整的财务年度的业务要求就是一个例子。在此应用场景中,新的财务年度是按星期或按月逐渐形成一个完整财务年度的。然后,几乎立刻删除最早的一个财务年度。所有这些应用场景都可以通过用于 Project REAL 的不同的滑动窗口实现方案来完成。不同形式之间的区别在于执行合并/切换操作的方式和时间。

Barnes and Noble 尚未累积够足以值得进行数据存档的销售量或库存量数据。因此,我们缩短了删除周期以便能够测试滑动窗口的实现方案。该过程由参数驱动,并可以方便地进行修改以调节时间选择。

旧数据

经常谈论但很少实施的一种概念是在速度最快和可用性最高的磁盘子系统上维护最活跃的数据,在速度较慢和/或可用性较低的成本较低的磁盘上驻留不太活跃的数据。这一概念在数据仓库中尤其有用,因为数据仓库具有极高的磁盘存储要求,并且其数据通常需要多年保持在线。我们已经发现,前一年或前两年的数据将会存在活动热点。但是这并不意味绝对不会对旧数据进行查询或规定不允许使用旧数据。为了管理维护这种基础结构所需的开销,我们在 Project REAL 中实现了一种机制,以便在增量处理过程中将分区从成本较高的磁盘子系统移到成本较低的磁盘子系统。这是在同时添加和删除了分区的一个增量处理过程中完成的。

移到成本较低的磁盘在理论上有些复杂,但是在实际中却相对简单一些。主要应记住一点,我们是真正将数据从一个磁盘子系统移动到另一个。这会是一项成本很高的操作,尤其当移动在数据仓库中找到的大量数据时。我们选择每个星期移动一个分区以使任一给定时间内数据的移动量最小化。

现在来看看理论上的复杂性。分区方案定义了分区函数中所定义的分区在磁盘上的布局方式。一旦创建了分区方案,则除了指示新分区将位于的位置以外,不能以任何方式重命名或修改该分区方案。在分区函数中拆分和合并分区可以添加或删除分区,但不会影响现有分区的位置。因此,要“移动”分区,我们必须创建新的分区方案来指示分区在磁盘上的新布局。

图 9

图 9:将旧数据移动到成本较低的磁盘
查看实际尺寸图像

下面完整概述了执行旧数据移动所需的步骤。最初,此过程看起来有些复杂,尤其是(在 Project REAL 中)当销售量分区表中的分区超过 150 个时!因为上述所有步骤都是元数据步骤(除了数据移动步骤以外),所以实际的运行速度很快。

1.

根据现有分区函数创建新的分区方案,除了正在移动的分区以外,新的分区方案与现有分区方案完全相同。分区方案定义将指示将分区边界移动到成本较低的磁盘上的文件组中。

2.

在新的分区方案顶部创建一个新的分区表。

3.

遍历每个分区并从旧分区切换到新分区(两个分区表使用同一个分区函数)中的同一分区号,直至到达要移动的分区。着色框指的是已填充的分区,空白框指的是空白分区。

4.

因为要移动数据,所以需要显式复制要移动的分区。可以通过以下方式执行此操作:使用 INSERT INTO..SELECT 语句直接将数据从旧分区复制到新分区,或者也可以使用 SELECT INTO 语句选择驻留在同一文件组的某个外部表作为目标分区。如同在初始加载中一样,SELECT INTO 远比 INSERT INTO 的性能好,所以我们选择前一种方法。

5.

当使用 SELECT INTO 方法时,我们需要在新的分区表中将外部表切换到其最终目标。

6.

现在,我们来遍历当前分区方案中的其余分区,像在步骤 3 那样将这些分区切换到新的分区表中。

7.

通过以下方式进行清理:删除旧的分区表和分区方案,将新的分区表重命名为原分区表的名称。

代码示例

下面将深入研究以上概述的对旧数据进行管理的过程。

1.

创建新的分区方案

除更改了定义分区“老化”时间的日期边界以外,新的分区方案与现有分区方案完全相同。其名称后缀是当前周末的日期,所以它是唯一的。由于分区方案名称无法更改,因此此名称将保留到下一个老化过程,即当新的分区方案替代此分区方案时。

在典型的、将会创建新分区的每周过程中,只有一个分区会从“活动”文件组移到“老化”文件组。将对元数据创建一个光标以遍历边界并为新的分区方案生成脚本。尽管光标由于低性能而通常在任何 ETL 过程中都不是好方法,但在这种情况下,它们仅用于遍历少量的元数据对象。请注意,在两个分区方案中,除了要从“活动”文件组移到“老化”文件组的分区以外,所有文件组必须保持一样。用于实现此目的的代码如下所示:

DECLARE CurrentSchemePartitions CURSOR FOR 
SELECT FileGroupName, Boundary 
FROM dbo.fn_Get_FileGroupsByPartitionBoundary(@psOld_Scheme_Name)
ORDER BY Boundary ASC 

OPEN CurrentSchemePartitions

SET @psSQL_Text = 'CREATE PARTITION SCHEME ' + @psNew_Scheme_Name + '  
AS PARTITION pf_Range_Fact 
TO ('

   FETCH NEXT FROM CurrentSchemePartitions INTO @psFG_Name, @pnBoundary_Date

   WHILE @@FETCH_STATUS = 0
   BEGIN
      -- If the partition boundary is less than the beginning date, use the file   
      -- group for the new partition to move into the Agedd area
      IF @pnBoundary_Date < CONVERT(int, CONVERT(char(10), @pdLogical_Date, 112))
      BEGIN
  SET @psSQL_Text = @psSQL_Text + @psFG_Name + ', '   
         SET @psAged_FG_Name = @psFG_Name
      END
      -- If the partition boundary is less than or equal to the Aged date and was 
      -- previously in one of the "Current" filegroups, script the partition to 
      -- the Aged filegroup that will be relinquished when the old partition drops  
      -- off.
      ELSE IF @pnBoundary_Date <= CONVERT(int,CONVERT(char(10),@pdAged_Date, 112)) 
         AND @psFG_Name LIKE @psActive_FG_Prefix + '%'
      BEGIN
         SET @psSQL_Text = @psSQL_Text + @psAged_FG_Name + ', '
  SET @psActive_FG_Name = @psFG_Name
      END
      ELSE   
         SET @psSQL_Text = @psSQL_Text + @psFG_Name + ', '

      FETCH NEXT FROM CurrentSchemePartitions INTO @psFG_Name, @pnBoundary_Date

   END

   -- !!When we are done, we need to add a additional partition to the scheme. 
   -- This is for the right-most partition, which was not represented in our 
   -- cursor query because it is not in the partitioning function. Since we are 
   -- left partitioning, data will ever be in this final partition.
   SET @psSQL_Text = @psSQL_Text + '[Primary])'
   EXEC (@psSQL_Text)

   CLOSE CurrentSchemePartitions
   DEALLOCATE CurrentSchemePartitions

2.

创建新的分区表

新的分区表定义看起来与旧的定义完全一样。唯一的区别是它将基于刚才创建的新的分区方案来定义。还需要创建索引以便可以将分区从旧的分区表直接切换到新的分区表。

3.

创建了一个新光标,它与在步骤 1 中使用的光标一样。当遍历此光标时,我们会将每个分区直接切换为新表中等同分区。因为新的分区方案和旧的分区方案基于同一个分区函数,所以知道源分区号和目标分区号是相同的。

SELECT @PartitionNum = $partition.pf_Range_Fact(@pnBoundary)
SET @psSQL_Text = 'ALTER TABLE ' + @psPartitioned_Table_Name + 
' SWITCH PARTITION ' + CONVERT(varchar(3), @PartitionNum) + ' TO ' 
+ @psNew_Partitioned_Table_Name + ' PARTITION ' + 
CONVERT(varchar(3), @PartitionNum)
EXEC (@psSQL_Text)

4.

如果要移动分区,我们需要将数据复制到具有相同结构的一个新的外部表中。如上所述,最有效的复制方法是执行 SELECT INTO 操作,接着创建检查约束和索引。然后,将该外部表(现在是分区表,在创建索引以后)切换到在步骤 2 中创建的分区表。用于执行这些步骤的代码段如下所示:

SET @pnAged_Boundary_Date = @pnBoundary 

-- Get the name of the Aged FG that the moving partition will reside on by 
-- looking it up on the new partition scheme
SELECT @psNew_FG_Name = dbo.fn_Get_FileGroupForBoundary(@psNew_Scheme_Name, 
@pnBoundary)

-- Change the default filegroup to the filegroup the moving partition will 
-- reside on so the SELECT INTO will create the table on the correct filegroup.
EXEC etl.up_SetDefaultFG @pnBoundary, @psNew_Scheme_Name

IF (SELECT COUNT(*) FROM sys.tables WHERE name = 'MovingPartition') > 0
DROP TABLE MovingPartition

-- Copy the data from the moving partition on the old table to a temporary 
-- partition on the new filegroup.
SELECT @PartitionNum = $partition.pf_Range_Fact(@pnBoundary)
SET @psSQL_Text = 'SELECT * INTO MovingPartition FROM ' + 
@psPartitioned_Table_Name + 'WHERE $partition.pf_Range_Fact(SK_Date_ID) = ' 
+ CONVERT(varchar(4), @PartitionNum)
EXEC (@psSQL_Text)

-- Since constraints and indexes were lost during the SELECT INTO, create them 
-- to match those on the destination partitioned table.
SET @psBoundary = @pnBoundary
SET @pdWeek_Begin = SUBSTRING(@psBoundary, 5, 2) + '/' +
SUBSTRING(@psBoundary, 7, 2) + '/' + 
SUBSTRING(@psBoundary, 1, 4)

SET @psSQL_Text = 'ALTER TABLE MovingPartition WITH CHECK 
ADD CONSTRAINT MovingPartition_Date CHECK  
(SK_Date_ID BETWEEN ' + 
CONVERT(varchar(8), DATEADD(dd, -6, @pdWeek_Begin), 112) + ' AND ' + 
CONVERT(varchar(8), @pnBoundary, 112) + ')'
EXEC (@psSQL_Text)

EXEC etl.up_CreateIndexes 'MovingPartition', @psNew_FG_Name

-- Get the partition number for the moving partition and switch it in to the 
-- new partitioned table
SET @psSQL_Text = 'ALTER TABLE MovingPartition SWITCH TO ' + 
@psNew_Partitioned_Table_Name + ' PARTITION ' + 
CONVERT(varchar(3), @PartitionNum)
EXEC (@psSQL_Text)

DROP TABLE MovingPartition

5.

删除或重命名旧的分区表

6.

重命名新的分区表

意见和建议

根据对一组完整数据进行的试验,我们得出了一些意见。这些意见主要与性能比较有关。下面将介绍这些意见。

共享分区函数

从逻辑上讲,三个事实数据表使用的分区函数是相同的。我们决定以相同的方式对它们进行分区以方便它们的连接。例如,假设我们发出一个关系查询,要求获得本年度每个月某项的销售量与库存量比较。SQL Server 可以识别出这两个分区表是对齐的,这意味着它们共享同一个分区函数。当连接两个对齐的分区表时,优化器允许在分区内进行连接,然后将子集连接结果放在一起。当我们说两个表共享同一个分区函数时,并不表示它们必须真正共享同一个分区函数,而是指它们各自的分区函数必须具有相同的分区数,并且其分区键必须是同一数据类型。遵循这些规则的最简单的方法就是照字面意思共享同一个分区函数。

共享同一个分区函数会带来一些问题。当拆分最后一个分区以添加新的边界时,引用该分区函数的所有分区方案都必须已识别出下一个分区所在的位置。当通过合并函数来删除分区时,所有相关分区方案应该已将该分区腾空。如果第一个分区并非在所有引用该分区函数的表中均为空,则合并操作的物理结果是将行从删除的分区移到要合并到的分区位置。这不是一个严重的问题,但是移动行时会使性能降低,更重要的是,实际上并不会删除我们要存档的行。

为了演示下面的内容,我们在左侧列出了分区函数,在最右侧几列中列出了三个分区方案。当我们拆分最后一个分区为切换入新数据做准备时,必须为全部三个分区方案设置相应的 NEXT FG 以使新数据位于正确的位置。当我们合并第一个分区为删除在 2002 年 5 月 1 日结束的那一周做准备时,使用这三个方案的所有分区表中的第一个分区数据必须已被切换出且必须为空。例如,如果 Tbl_Fact_Store_Inventory 表仍具有此星期的数据,那么合并操作将会使此数据移动到 Aged FG 3 中。

分区函数 分区方案
Pf_Range_Factps_FactStoreSalesps_FactStoreInventoryps_FactDCInventory

01/05/2002

Aged FG 1

Aged FG 2

Aged FG 3

01/12/2002

Aged FG 2

Aged FG 3

Aged FG 4

12/18/2004

Active FG 1

Active FG 2

Active FG 3

12/25/2004

Active FG 2

Active FG 3

Active FG 4

01/01/2005

Next FG

Next FG

Next FG

尽管通过创建单独的分区函数可以完全解决此问题,但是无论如何都必须执行相同的操作 - 唯一的好处是这些操作不必一起执行。分隔分区函数还可能会引起事实数据表在任一给定时间的分区数存在差异。这将会消除以对齐的表开头所带来的好处。

索引的创建

在分区表的初始填充过程中,存在这样一个问题:是在最开始还是在加载了分区表之后对该分区表创建索引?最初,这一决定好像对性能影响甚微。选项如下所示:

选项 1 - 在加载之前对分区表创建索引

1.

创建分区表

2.

对分区表创建索引

3.

为每个源表

a.

创建外部表

b.

用 SELECT INTO 语句选择外部表

c.

创建 CHECK 约束

d.

创建与分区表上的索引相匹配的索引

e.

将外部表切换到分区表中的相应分区

选项 2 - 在加载之后对分区表创建索引

1.

创建分区表

2.

为每个源表

创建外部表

a

用 SELECT INTO 语句选择外部表

b

创建 CHECK 约束

c

将外部表切换到分区表中的相应分区

3.

对分区表创建索引

带下划线的步骤指明了两个选项之间的差异。由于索引在任何一种情况下都是在加载了数据后创建的,因此两个选项之间应该不存在实质性的差异,但实际上是存在的。经证明,选项 2 的操作速度快了 70%,因此我们选择了该选项来进行初始加载。对于增量加载,我们不会选择这两个选项中的任何一个,因为我们最终要切换到已经创建了索引的分区表。这样一来,我们就必须在切换之前对外部表创建匹配的索引。

如果使用选项 1,则不管是用于初始加载还是增量加载,应确保对目标分区表所使用的分区方案创建索引。实际上,这将使外部表成为加载了单个分区的分区表。这样一来,您就必须在切换期间指明外部源表和目标表的分区数。

用于元数据查询的用户定义函数

有几种新的数据管理视图 (DMV) 用于表示分区函数和分区方案的元数据。我们将这些视图用于实现方案的各个部分,但同时通过创建以下所述的两个用户定义函数来简化此过程。因为在开发期间没有介绍这些 DMV,所以它们的正确用法是通过跟踪对分区函数和分区方案对象编写 CREATES 脚本时 SQL Server Management Studio 所生成的查询来确定的。

第一个函数将针对一种分区方案返回所有文件组及其相关联的分区边界(在我们的示例中是上边界,因为我们使用的是 LEFT 分区函数)的表结果集。

CREATE FUNCTION dbo.fn_Get_FileGroupsByPartitionBoundary(@SchemeName varchar(50))
RETURNS TABLE
AS RETURN
(
SELECT sf.name AS FileGroupName, 
CONVERT(int, sprv.value) AS Boundary
FROM sys.partition_schemes AS sps
INNER JOIN sys.partition_functions AS spf 
ON sps.function_id = spf.function_id
INNER JOIN sys.destination_data_spaces AS sdd 
ON sdd.partition_scheme_id = sps.data_space_id 
AND sdd.destination_id <= spf.fanout
INNER JOIN sys.partition_range_values sprv 
ON sprv.function_id = spf.function_id
AND sprv.boundary_id = sdd.destination_id
INNER JOIN sys.filegroups AS sf 
ON sf.data_space_id = sdd.data_space_id
WHERE sps.name= @SchemeName
)

第二个用户定义函数将返回指定边界之前或当日的最后一个文件组。

CREATE FUNCTION dbo.fn_Get_FileGroupForBoundary (@SchemeName varchar(50), @Boundary int)RETURNS varchar(50)WITH EXECUTE AS CALLERAS-- Find last filegroup prior to or equal to specified boundaryBEGINDECLARE @FileGroupNamevarchar(50)SELECT TOP 1 @FileGroupName = sf.name FROM sys.partition_schemes AS spsINNER JOIN sys.partition_functions AS spf ON sps.function_id = spf.function_idINNER JOIN sys.destination_data_spaces AS sdd ON sdd.partition_scheme_id = sps.data_space_id AND sdd.destination_id <= spf.fanoutINNER JOIN sys.partition_range_values sprv ON sprv.function_id = spf.function_idAND sprv.boundary_id = sdd.destination_idINNER JOIN sys.filegroups AS sf ON sf.data_space_id = sdd.data_space_idWHERE sps.name = @SchemeName AND sprv.value <= @BoundaryORDER BY sprv.value DESCRETURN(@FileGroupName)END

多维数据集分区

多维数据集分区的好处

除了对关系数据仓库进行分区以外,我们还选择了对 Analysis Services 多维数据集进行分区。更准确地说是在 Analysis Services 2005 中,对度量值组进行了分区,但我们通常将整个过程称为“多维数据集分区”。对较大的多维数据集进行分区有很多好处,与对关系数据仓库进行分区带来的好处相似。最明显的一个好处在于多维数据集维护方面。多维数据集可完整处理或按分区逐步处理。可以有选择地处理带有若干分区的多维数据集。当只有一个或少数几个分区会受到对源表所做更改的影响时,这样做的好处尤其明显。这将大大减少增量处理的批处理窗口。各个分区还具有自己的聚合和存储模式。当按日期进行分区时,可以在较低的聚合级别或使用不同的存储模式 (ROLAP/HOLAP/MOLAP) 对较早的分区进行重新处理,以便减少所需的磁盘空间和处理时间。在分区级别还定义了主动缓存设置。分区甚至可以作为远程分区存储在远程服务器上。因为只要将较早的分区删除即可,而不必重新处理整个度量值组来识别基础关系数据源中要存档的数据,因此更易于管理。如果为了基于分区键限制数据而编写多维数据集查询,则还应考虑查询性能。

Analysis Services 2005 中的更改

在 Analysis Services 2000 中适用的有关分区的大多数原则在 Analysis Services 2005 中也是贴切的。新版本中进行了一些更改,大多数是对前一版本的改进。

首先,分区定义在度量值组级别,而非多维数据集级别上。多维数据集中包含一个或多个度量值组,它们与其源表中的逻辑事实表相关。新版本中做出了一个绝妙的性能改进:对多维数据集或度量值组的处理会自动引起对基础分区的并行处理。在 Analysis Services 2000 中,分区是串行处理的,除非某个自定义 DSO 程序(例如并行处理实用程序,可从 Microsoft 网站免费下载)明确强制执行并行处理。

在 Analysis Services 2000 中,仅当多维数据集分区上定义了数据切片以使 OLAP 引擎了解各个分区中包含的数据时,进行分区才有利于提高查询性能。这类似于对分区视图定义检查约束,以使 SQL Server 优化器能够将根据分区列查询的表数最小化。在 Analysis Services 2005 中,MOLAP 多维数据集不再需要数据切片来用于此目的。这是因为 MOLAP 多维数据集包括试探法以映射各个分区中包含的数据。请注意,还原为 ROLAP(例如在重新生成主动缓存的过程中)的任何多维数据集将无法使用这些试探法,并且如果没有定义数据切片,性能就会受到影响。因此,如果多维数据集必然会还原为 ROLAP,最好还是定义数据切片。

Analysis Services 2000 多维数据集中的源数据是直接从源关系数据库中的表或视图定义的。在此过程中,可以定义筛选器来指定部分表或视图。例如,如果使用的是分区视图,该分区视图的名称可以用作 Analysis Services 2000 分区的源;同时使用了一个单独的筛选器来将 AS 分区中的数据限制为该分区视图的基础表中的数据。在 Analysis Service 2005 中,指定的分区源可以是表/视图或查询。如果部分基础表或视图将用于填充分区,则分区定义将指定称为“绑定查询”的查询。

最后,在 Analysis Services 2005 中,用于创建分区的自动化选项更多了。以前,DSO(决策支持对象)用于“克隆”现有分区,更改相关属性以及保存新的分区。DSO 已被 AMO(分析管理对象)替代。来自 AMO 的所有请求最终将转换为 XMLA (用于 Analysis 的 XML) 脚本。因为 SSIS 能够执行本机 XMLA,所以它是另一个选项。哪一个选项是首选呢?这正是我们要确定的。

有关 Analysis Services 分区策略的讨论

在 Analysis Services 中实现分区的第一步是确定分区策略,即,分区应基于什么边界来划分。如同在关系数据仓库中一样,常见的策略是基于日期进行分区。因为通常数据是根据日期逐步加载的,所以这就会简化处理过程。如上所述,进行备份后只要将旧分区删除即可,因此这种方式还会简化存档。将 Analysis Services 多维数据集用与基础关系数据仓库相同的标准进行分区是有益的。这样一来,就可以在单个过程中执行数据存档,该过程将同时从数据仓库和多维数据集中删除相应的分区。这正是 Barnes and Noble 选择用于 Project REAL 的策略。

Barnes and Noble 的实现方案在每个事实表顶部包括一个视图以添加相关维度成员的一些附加信息。此视图在 Analysis Services 2000 中用作多维数据集分区的源“表”。随着分区表的引入,视图的数量从每个事实表每星期一个视图(229 个视图)下滑到每个事实表一个视图(3 个视图)。Analysis Services 2005 分区可用 WHERE 语句指定针对相关视图的查询,以便将数据限制到单个分区,例如:

SELECT [SK_Store_ID], [SK_Parent_Store_ID], ...
FROM [dbo].[vTbl_Fact_Store_Inventory] 
WHERE [SK_Date_ID] BETWEEN 20041212 AND 20041218

在 Analysis Services 2005 中,可以使用两种方法来使多维数据集的创建和处理自动化。以下几节将介绍有关这两种方法的详细信息(包括其优、缺点)。

XML/A 概述

第一种方法是 XMLA,或更具体地,ASSL。XMLA 是用于查询 OLAP 数据的一种 XML 规范,它是在 2001 年 4 月首次发布的(可以在 www.xmla.org 上找到有关 XMLA 规范的详细信息)。ASSL 专用于 Analysis Services,是用于 OLAP 的一种 XML DDL 规范。XMLA 是用于 Analysis Services 2005 的本机数据交换协议。与 Analysis Services 进行的所有通信最终通过 XMLA 来执行。由于不需要进行转换,因此这是与 Analysis Services 2005 进行通信的最快捷的一种方法。但在大多数元数据操作中,这可能并不是关键的因素,因为不会有大量查询提交到 Analysis Services,此转换成本将会很低。

最初 XMLA 脚本看起来有些复杂。像其他任一 XML 脚本编写语言一样,XMLA 中的元素以层次结构来表示,并具有自描述性。该语言比较繁琐,我们很难从头开发。幸运地是,Analysis Services 2005 给我们开了一个好头。

XML/A 实现方案

在 Analysis Services 2005 中,编写对象(例如多维数据集、维度和分区)的能力大大提高了。相比之下,Analysis Services 2000 不具有任何现成的脚本编写功能。此脚本编写功能使得使用 XMLA 成为一个合理的选择,因为不需要特别熟悉 XMLA 规范。可以在 SQL Server Management Studio 中通过打开新的“Analysis Services XMLA 查询”窗口来执行 XMLA。还可以在 SQL Server Integration Services (SSIS) 中通过“Analysis Services 执行 DDL”任务来执行它。这使得我们可以通过 XMLA 方便地使分区的创建和处理自动化。

第一步是为每个多维数据集度量值组生成 XMLA 脚本。此步骤通过 SQL Server Management Studio 来执行,要执行的操作为:导航到度量值组中的一个分区,单击右键,然后选择“将分区脚本编写为”。下一步要查看 XMLA 以了解需要对每个分区进行的更改。可以通过将脚本粘贴在“SQL Server Management Studio XMLA 查询”窗口中来实现此目的。此脚本随后将被粘贴到 SSIS 脚本编写任务中,各个分区之间所有不同的文本将被替换为根据分区修改的变量。该 XML 字符串将保存为在“Analysis Services 执行 DDL”任务中执行的 SSIS 变量。以下脚本是从为 REAL Warehouse 多维数据集中的仓库库存量度量值组编写分区脚本的 SSIS 脚本编写任务得出的。针对分区名称和分区 ID 创建了变量,并针对关系源创建了查询。

sXMLA = sXMLA & "<Create 
xmlns=""http://schemas.microsoft.com/analysisservices/2003/engine"">"
sXMLA = sXMLA & "    <ParentObject>"
sXMLA = sXMLA & "        <DatabaseID>REAL Warehouse Partitioned</DatabaseID>"
sXMLA = sXMLA & "        <CubeID>REAL Warehouse</CubeID>"
sXMLA = sXMLA & "        <MeasureGroupID>Store Inventory</MeasureGroupID>"
sXMLA = sXMLA & "    </ParentObject>"
sXMLA = sXMLA & "    <ObjectDefinition>"
sXMLA = sXMLA & "        <Partition xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" 
xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">"
sXMLA = sXMLA & "            <ID> & sPartitionName & </ID>"
sXMLA = sXMLA & "            <Name> & sPartitionName & </Name>"
sXMLA = sXMLA & "            <Annotations>"
sXMLA = sXMLA & "                <Annotation>"
sXMLA = sXMLA & "                    <Name>AggregationPercent</Name>"
sXMLA = sXMLA & "                    <Value>13</Value>"
sXMLA = sXMLA & "                </Annotation>"
sXMLA = sXMLA & "            </Annotations>"
sXMLA = sXMLA & "            <Source xsi:type=""QueryBinding"">"
sXMLA = sXMLA & "                <DataSourceID>REAL Warehouse</DataSourceID>"
sXMLA = sXMLA & "                <QueryDefinition> & sQuery & "</QueryDefinition>"
sXMLA = sXMLA & "            </Source>"
sXMLA = sXMLA & "            <StorageMode>Molap</StorageMode>"
sXMLA = sXMLA & "            <ProcessingMode>Regular</ProcessingMode>"
sXMLA = sXMLA & "            <ProactiveCaching>"
sXMLA = sXMLA & "                <SilenceInterval>PT10M</SilenceInterval>"
sXMLA = sXMLA & "                <Latency>-PT1S</Latency>"
sXMLA = sXMLA & "                <SilenceOverrideInterval>-PT1S</SilenceOverrideInterval>"
sXMLA = sXMLA & "                <ForceRebuildInterval>-PT1S</ForceRebuildInterval>"
sXMLA = sXMLA & "                <Source xsi:type=""ProactiveCachingInheritedBinding"" />"
sXMLA = sXMLA & "            </ProactiveCaching>"
sXMLA = sXMLA & "            <EstimatedRows>2000000</EstimatedRows>"
sXMLA = sXMLA & "            <AggregationDesignID>AggregationDesign 2</AggregationDesignID>"
sXMLA = sXMLA & "        </Partition>"
sXMLA = sXMLA & "    </ObjectDefinition>"
sXMLA = sXMLA & "</Create>"

可以通过以下步骤以 XMLA 编写多维数据集处理脚本:导航到 SQL Server Management Studio 中的一个度量值组分区,单击右键,选择“处理”,然后在出现的对话框顶部按“编写脚本”按钮。用于处理多维数据集的 XMLA 脚本示例如下所示。

<Batch xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">
  <Parallel>
    <Process xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Object>
        <DatabaseID>REAL Warehouse Partitioned</DatabaseID>
        <CubeID>REAL Warehouse</CubeID>
        <MeasureGroupID>Store Inventory</MeasureGroupID>
        <PartitionID>Store Inventory WE 2004 12 11</PartitionID>
      </Object>
      <Type>ProcessFull</Type>
      <WriteBackTableCreation>UseExisting</WriteBackTableCreation>
    </Process>
  </Parallel>
</Batch>

AMO 概述

分析管理对象 (AMO) 是一整套用于管理 Analysis Services 的 .NET 对象。AMO 替代了 SQL Server 7.0 中的 Analysis Services 2000 和 OLAP Services 所使用的 DSO 对象模型。正如 Analysis Services 2000 中的所有 Analysis Manager 操作是通过 DSO 实现的,在 Analysis Services 2005 中,用于管理 Analysis Services 实例和数据库的所有机制是使用 AMO 实现的。AMO 位于 XMLA 的顶层,并最终生成 XMLA 来执行与 Analysis Services 实例的所有通信。这使得它的性能略低于 XMLA。但除非存在许多 AMO 方法调用,否则它们之间的性能差异似乎是察觉不到的。

SQL Server 2005 中的其他增强功能使得使用 AMO 比使用其前任 DSO 更简单。因为自动化任务经常是在 DTS 中实现的,所以我们要转移到 VBScript 开发环境中。此环境中没有在 SSIS 脚本编写任务中看到的编码(智能感知、颜色编码)功能的丰富设置,该功能使用 VSA (Visual Studio for Applications) 接口。因为联机丛书中的 AMO 文档还很少,所以在 Project REAL 中,AMO 代码的开发很大程度上依赖于此功能。

DSO 最迟钝的方面可能是用于向下导航到分区对象的 MDStores 接口实现方案。这种情况在 AMO 中不复存在,数据库导航直观得多了。随后会在一个代码示例中对此进行演示。

要注意的一点是:Barnes and Noble 当前的 Analysis Services 2000 实现方案不通过 DSO 和 DTS 创建多维数据集分区,而是每年手动创建一次分区;因为 Analysis Services 2000 本身无法并行处理分区,所以通过并行处理实用程序进行处理。Analysis Services 2005 中的增强功能使我们能够方便地使这些处理自动化,并降低管理开销。

AMO 实现方案

我们的目标是能够使用 AMO 执行以上使用 XMLA 执行的功能。事实上,我们可以根据 AMO 对象模型中固有的循环机制改进功能。我们遍历了每个度量值组并检查该度量值组是否引用了给定的事实表。如果引用了,我们就使用给定的处理日期来确定是否已经存在关联的分区。如果不存在该分区,则需要创建它。

利用 XMLA 实现方案,通过运行以前生成的脚本并更改 XML 中指定分区名称、分区 ID 和查询定义的元素创建了分区。AMO 提供了使用“克隆”方法复制度量值组中某个现有分区的功能。并非通过显式设置代码中的分区属性来创建分区,而是使用“克隆”方法复制分区集合中最后一个分区的所有内容,并更改在 XMLA 脚本中修改的那些属性。

随脚本编写任务实现的 VSA 环境还允许我们引入更丰富的错误处理功能。因为无法从全局处理错误,所以 DTS 中的 VBScript 代码要求在执行每个操作后都要检查是否存在错误。这使得代码更为复杂、可读性更差。在 SQL Server Integration Services (SSIS) 脚本编写任务中使用 Visual Basic .NET,我们可以在一组语句中一致使用 Try..Catch 语句来处理错误。我们还使用此功能来声明和初始化变量,以提高代码的可读性。

我们使用的另一种技术是从 SSIS 连接管理器中收集已经存在的连接信息。这意味着将此数据包部署到 QA 和生产环境中时,我们只需要在一个地方修改服务器和数据库信息。SSIS 中的配置也可以实现这一技术。

以下是用于实现分区创建功能的核心代码段。

Try

   Dim oDB As Database = oServer.Databases(sDatabase)
   Dim oCube As Cube = oDB.Cubes("REAL Warehouse")

   Dim dLogicalDate As Date = CDate(Dts.Variables("vdtLogical_Date").Value)
   Dim sTableName As String = CStr(Dts.Variables("vsPartitioned_Table_Name").Value)
   Dim sWeekEnd As String = GetIntegerDateFormat(dLogicalDate)

   ' Find all measure groups that reference the table being processed
   For Each oMeasureGroup In oCube.MeasureGroups
  oPartition = oMeasureGroup.Partitions(0)
      oQueryBinding = oPartition.Source
      If oQueryBinding.QueryDefinition Like "*" & sTableName & "*" Then
         ' Get the relevant boundary partition name and check to see if it 
         ' already exists
         sPartitionNew = GetNewPartitionName(sWeekEnd, oPartition.Name)
         oPartition = oMeasureGroup.Partitions.FindByName(sPartitionNew)
         If oPartition Is Nothing Then
            ' Get the last partition
            oPartition = oMeasureGroup.Partitions(oMeasureGroup.Partitions.Count - 1)
            ' Clone the properties from the last partition to the new partition.
            oPartitionNew = oPartition.Clone
            oPartitionNew.ID = sPartitionNew
            oPartitionNew.Name = sPartitionNew
            oQueryBinding = oPartitionNew.Source
            oQueryBinding.QueryDefinition = GetNewQuery(oPartition.Source, sWeekEnd)
            oMeasureGroup.Partitions.Add(oPartitionNew)
            oPartitionNew.Update()
         End If
      End If
   Next
   Dts.TaskResult = Dts.Results.Success
Catch ex As Exception
   Dts.Events.FireError(0, "Create Partition", ex.Message, "", 0)
   Dts.TaskResult = Dts.Results.Failure
End Try
If oServer.Connected Then
   oServer.Disconnect()
End If

VSA 中存在一个问题,要求所有引用的程序集位于 <windows 路径>/Microsoft.NET/Framework 路径的相应版本子目录中。必须手动将 AMO 和 SMO 程序集从 <SQL Server>/90/SDK/Assemblies 目录复制到上述目录中。随着 SQL Server 后续版本的安装,可能会创建新的 VSA 版本目录,并且可能会对程序集进行更改,这将需要重新复制这些文件。对于本文引用的 AMO 编码,只有 AMO 程序集 (Microsoft.AnalysisServices.DLL) 是必需的。

确保将相应的文件复制到 VSA 可以识别的位置后,必须在脚本编写任务中添加对它们的引用。要执行此操作,只需右键单击“项目资源管理器”中的“引用”,并选择“添加引用...”,然后找到“分析管理对象”引用并添加该引用。然后,在脚本的开头添加“Imports Microsoft.AnalysisServices”一行,如下图所示。

图 15

图 15:添加脚本编写任务引用
查看实际尺寸图像

意见和建议

XMLA 脚本编写和 AMO 选项很容易实现,尤其是在利用 SSIS 时。下面介绍了对每种方法的一些意见。哪一种方法更为理想要针对特定的实现方案来看。总的来说,我们发现 AMO 具有的好处多于 XMLA,如下所述。

对 AMO 的意见

优点:

更加精致和简单明了 - 尽管这是因人而异的,但却是大多数人的看法。

可以用来包含将来的对象 - 回顾 AMO 代码,您会发现对每个度量值组中的第一个分区进行了检查,以检查是否存在对所传递的事实表的查询引用。由于多维数据集设计良好,因此不可能会添加其他多维数据集来引用同一事实表,它消除了发生这种情况的可能性。还消除了重命名度量值组的可能性;在 XMLA 实现方案中,度量值组的名称经过硬编码。

动态合并分区属性更改 - 因为已复制了最后一个分区,所以对聚合设计、存储模式、主动缓存等进行的任何更改都会被复制到新的分区。这在多数情况下是理想的。

全部代码都位于一个易于读取的脚本编写任务中;XMLA 实现方案则需要一个脚本编写任务和一个单独的执行 Analysis Services DDL 任务。

在 AMO 中,可以在单个任务中结合其他工作(例如处理)。在 XMLA 中,不论通过执行 Analysis Services DDL 任务还是 Analysis Services 处理任务进行处理,都需要作为一个单独的任务;与此不同的是,可以通过向 AMO 脚本中额外添加一行来执行处理。

缺点:

每发行一个新的 SQL Server 版本,必须手动将程序集复制到 Microsoft .NET

对 XMLA 的意见

优点:

1.

一切都显露在外 - 基础对象的所有相关属性都显露在外,使我们可以很容易确定应该更改的内容和不应该更改的内容。

2.

最低级别 - 因为 XMLA 是 Analysis Services 的本机通信协议,所以速度最快。

缺点:

必须手动编写脚本 - 实际上,并非严格要求这样做。可以开发通用的脚本,该脚本将使用变量来替换所有属性,这些属性随着度量值组的不同而不同。这些属性要么必须是针对每个度量值组经过硬编码的,要么是使用 AMO 从每个度量值组中提取的。其他度量值组仍需手动添加到脚本中。

仍然需要使用 AMO 来检查是否存在分区 - 在我们的示例中,我们希望 ETL 过程可以重新开始,所以在开始创建分区之前,要检查是否预先存在目标分区。这只能通过 AMO 来完成。此代码自然会合并在 AMO 实现方案的分区创建代码中。

更改任何并非最初编写脚本的内容都将需要重新编写脚本或手动对脚本进行更改 - 这可能是使用 XMLA 脚本编写来使分区创建自动化存在的最大问题。在少数情况下,可能需要始终保持最初的、编写脚本的属性。这种情况使用 AMO 或 XMLA 都可以很容易地实现。

整体意见

两种方法都因 SSIS 中的许多增强功能而受益,即:

可在 SSIS 中方便地实现分区创建 - 尽管 DTS 提供了 VBScript 任务来进行 DSO 编码,但使用 VSA 环境作为开发环境来执行 SSIS 脚本编写任务具有一些好处。执行 Analysis Services DDL 任务提供了一种执行 XMLA 的非常简单的方法。

更好的错误处理和调试功能使得代码的读取更加容易,且代码的开发更加快速。

当完全使用 AMO 时,必须使用一种解决方法使 VSA 能够引用 AMO 程序集(请参阅对 AMO 的意见下的最后一个项目符号引导的内容)。

ETL 更改

至此已定义了所有用来实现增量分区维护的组件,我们需要将其集成回现有的 ETL 过程中。请记住,现有的实现方案为每个分区使用一个显式 SQL Server 2000 表。因为没有足够的历史数据足以需要实施分区存档,所以当前的 ETL 中不存在此过程。同样,也不存在实施数据老化的过程。

以下是对 Barnes and Noble 的仓库和 DC 库存量事实表的现有 ETL 过程的概述,该过程适用于关系分区的管理。

执行前处理

将“当前”表的内容复制到一个新的“已命名”表来反映前一周 (ex:Tbl_Fact_Store_Inventory_WE_2004_12_11)

对该“已命名”表创建索引(因为使用了 SELECT INTO 语句)

重新初始化“当前”表以反映下一周 (SK_Date_ID, Days_In_Stock, ETL_Load_ID)

执行后处理

图 16

图 16:Barnes and Noble 分区创建 - 准备工作
查看实际尺寸图像

销售量事实分区不能按等同的过程来创建,因为这些表是提前批量创建的。这样做是为了不必创建一个过程来逐步执行此操作。Project REAL 增量处理中包括销售量事实分区维护,因此无需手动维护。以下概述了对增量分区维护所做的修改:

1.

执行前处理 - 尚未更改

2.

将最后一个分区的数据复制到下一个文件组的新外部表中(我们可以在此步骤期间重新初始化诸如 SK_Date_ID 这样的列)

3.

对新的外部表创建索引(因为使用了 SELECT INTO 语句)

4.

拆分最后一个分区并切换新的外部表

5.

删除最早的分区并将存档分区移动到成本较低的磁盘 - NEW FUNCTIONALITY

6.

执行后处理

Barnes and Noble 对 Analysis Services 2000 多维数据集分区的维护当前不是在 ETL 过程中执行的。以后一年会创建销售量和库存量多维数据集分区,并且直到当前一周的数据加入到这些分区中才会对分区进行处理。由于我们可以方便地将多维数据集分区维护合并到 ETL 过程中,因此不再需要这样做。

附加要求

我们对生命周期管理的分区维护数据片段添加了两个附加要求。

1.

可重新开始性

出于分区维护方面的考虑,我们希望确保此过程可以重新开始。这意味着任何用于创建新分区、删除旧分区或老化分区的代码都要执行检查以查看是否已经存在此过程。

2.

对一周中的每一天的分隔(便于 SSI 数据包运行)和分区管理过程的调用

可以在一周中的任何一天调用分区维护 SSIS 数据包。存储过程将通过查询元数据来检查是否到执行任一分区维护函数的时间了。因此,如果处理时间是星期一,则还将执行检查以查看是否存在相关分区。这些查询运行得很快,并不会给日常处理增添很大的开销。这样就不再需要单独进行每日和每周 ETL 过程。

将表分区组件放在一起

当此功能实现自动化时,利用“滑动窗口”实现方案来合并数据移动活动将非常有吸引力。这会很快变得相当复杂,尤其是从以后维护的角度来看。此方法需要创建新的分区方案以包括新的分区并删除旧的分区。实际上,分区的添加或删除是在所有分区方案共享的分区函数级别进行的。当我们设法确定某个分区是否在旧方案中存在而不在新方案中存在(以及相反的情况)时,这将很快使代码变得复杂。基本上,将这两种情况区分开会使代码简单得多,并使得我们可以以物理方式分隔各个处理过程(如果业务需要指示这样做)。事实上,滑动窗口实现过程也被分为两个存储过程。这为进一步更改业务要求(有可能发生)提供了方便。例如,如果以后决定每周添加一次新的分区,但每年删除一次旧的分区,就可以更容易地实现此更改。创建了以下存储过程来封装增量分区维护逻辑:

up_CreateNewPartition – 基于逻辑日期(应用数据的日期),检查是否存在此日期的分区,如果不存在,则创建一个。如果存在一个库存量分区,用前一个分区的数据将该分区初始化,并更改相关列(例如 SK_Date_ID)。如果存在一个销售量分区,则无需执行任何附加步骤。

up_RemoveOldPartitions – 基于逻辑日期,检查是否存在应存档的分区。对于 Project REAL,我们仅删除了旧的分区,但可能存在要实现的磁带存档策略。

up_MoveAgedPartitions – 基于逻辑日期,检查是否存在应移动到成本较低的磁盘的分区。

这三个存储过程由父存储过程 up_MaintainPartitionedTable 调用。整个分区维护过程封装在一个单独的 SSIS 数据包中,总体 ETL 过程中将调用该数据包。

图 17

图 17:Barnes and Noble 分区创建 - 后续工作
查看实际尺寸图像

参考资料

Strategies for Partitioning Relational Data Warehouses in Microsoft SQL Server -
http://www.microsoft.com/technet/prodtechnol/sql/2005/plan/spdw.mspx

SQL Server 2005 Partitioned Tables and Indexes by Kimberly L. Tripp -
http://www.sqlskills.com/resources/Whitepapers/Partitioning%20in%20SQL%20Server%202005%20Beta%20II.htm

TechNet Webcast:SQL Server 2005 Series(10 部分中的第 6 部分):Managing Large Databases using Partitioning -
http://msevents.microsoft.com/cui/WebCastEventDetails.aspx?eventID=1032270016&Culture= zh-cn

结束语

Barnes and Noble 可以获得在 SQL Server 2005 中使用分区表所带来的许多好处。由于编译时间过长(有时达 30 秒),所以 Barnes and Noble 未实现分区视图。数据被分到了单独的表中,但这些表是分别管理的。ETL 过程需要通过编码来确定加载数据时要更新的相应表。分区表则没有此要求,这使得管理开销低得多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值