Project REAL 分析服务技术探讨

概述
这份白皮书提供了一个关于分析服务(Analysis Services)设计和在Project REAL中的最佳实践的技术讨论。它深入的讨论了每一类对象的细节,例如数据源、数据源视图、维度、层次、属性、度量组、分割表等等。并指出如何在关系型数据库分割表的基础上创建一个能自动创建度量组分割表的SQL Server 2005集成服务程序包。

内容目录
关于Project Real
绪论
和分析服务交互的三种方法
数据库设计
数据源和数据资源视图
数据源
最佳实践:当在标准安全模式下工作时,记住你的密码。当移动对象时候,你将经常需要输入密码。
数据资源视图
最佳实践
使用数据源视图扩展元数据(metadata)
从数据源视图中忽略对象
修改数据源视图
结论
维度(dimensions)
维度键
层次(hierarchies)
分析服务2005中的维度缓存
属性关联
最佳实践:多花点时间用于维度的设计,在维度种捕获这种属性关系
键的唯一性
最佳实践(必须的):你必须总是确保属性键的唯一性。
最佳实践:总是扫描你的维度,确保它们包含你预期的广泛的、甚至是分布的成员。
最佳实践:如果你告诉系统属性是关联的,则它们必须是关联的。
将虚拟维度转换成属性层次
最佳实践:将SQL Server 2000分析服务中的虚拟维度转换成属性层次
可能的命名冲突
将关系表中的列提升为多维度设计中的属性
和tinyint键不匹配的数据类型
未知成员
最佳实践:在可能的地方,创建你自己的未知成员。使用系统生成的未知成员。
时间智能向导
最佳实践:可能创建单机时间维度表的地方
最佳实践:在时间维度向导中,为各个属性输入键列(非名称列),例如年、月、周。
度量组
分割表
其它的Cube对象
服务器端设置
设计抉择
如何表示厂商
半可加减的存货度量
最佳实践:如果你使用半可加性的度量,请确认Cube包含的维度不超过一个。
结论
附录A:自动的分割表创建

关于Project Real
Project Real是微软为创建商业智能应用程序提供最佳实践而所做的努力。这些程序都是在Microsoft® SQL Server™ 2005基础上,在真实的客户背景上构建实施的。这就意味着真实客户数据是可以代入系统内部,并且可以应对客户在开发过程中将会遇到的同样的问题。这些问题包括:
•        模式设计- 关系型模式和分析服务型模式
•        数据抽取、数据转换、数据加载(ETL)过程的实现
•        客户端系统的设计与开发,包括数据报表和交互式的分析
•        产品系统的分级
•        运营系统的管理和维护,包括数据资料的不断更新
通过在这种真实部署环境中的工作经历,我们获得了如何使用这些工具的完整理解。我们的目标是全方位的关注大公司在他们自己实际部署过程中所遇到的所有问题。

这份白皮书提供了一个关于分析服务(Analysis Services)设计和在Project REAL中的最佳实践的技术讨论。我们深入的讨论了每一类对象的细节,例如数据源、数据源视图、维度、层次、属性、度量组、分割表等等。并指出了我们在前进过程中遇到的重要问题。

若要查看Rroject REAL的概述信息,可查看 Project REAL: Technical Overview 白皮书。有相当大一部分的资料、工具、和例子,都是在Project REAL的生命周期中产生的。为了找到最新的信息,可以到Project REAL Web site这个连接来察看相关的信息( http://www.microsoft.com/sql/bi/ProjectReal/)

备注:这篇文章仅仅是一个草案,它包括了一些建设性的实践方法,这些方法都是基于我们早先在SQL Server 2005的Community Technology Preview (CTP)工作中获得的经验。到产品发布之前,白皮书中所描述的都是准确的。文档中描述的产品功能性可能会有所变化。在将来,可能会提供更好的实践方案。SQL Server 2005是在我们对这些好的练习例程中用的开发工具。

绪论
这篇文章回顾了关于Project REAL分析服务的技术性设计,并且讨论了各种影响设计的问题。我们假定读者已经比较熟悉分析服务设计,并且实践过Project REAL所采用的模式。例如,我们假定读者已经知道多对多厂商维度的存在。我们的讨论主要关注为什么它会存在(以及我们在对设计进行定案之前所考虑的可供选择的办法)。
在本文中,我们检验了在多维度设计中应用到的各种类型的分析服务对象。从物理模式对象入手,例如数据源和数据源视图。接下来我们讨论在逻辑对象,例如维度,用户自定义的层次关系、属性层次、和度量组等等。接下来深入到度量组特征,例如分割、集合(aggregate)设计、以及前摄缓存(proactive caching)。这部分内容最后讨论了其它的逻辑设计,包括计算、关键性能指示器(KPIs)、活动、透视、定制程序集、用户自定义函数(UDFs)和MDX脚本等等。

最后一个章节中,我们详细讨论了在分析服务模式设计阶段,两种可选的、合理的设计方案。我们提供了目标,也是我们考虑要做的事情,也正是我们所实现的。

本篇以介绍服务端设置来结束,主要讨论了我们为什么要改变这些配置。

Project REAL设计强烈依赖于分割(partitioning),在所有的度量组中,定义了几百个这样的分割表,在附录A中,我们将展示我们是如何解决我们在各种数据库中创建和管理分割表带来的管理问题。

和分析服务交互的三种方法
有三种方法来和分析服务交互:SQL Server管理环境(Management Studio),项目模式下的商业智能开发环境(Business Intelligence Development Studio)和连接模式下的商业智能开发环境。我们将逐一的实施检验它们,并将向你描述如果你不能适当的结合这些工具方法,将带来的无穷麻烦。

SQL Server 管理环境(Management Studio)
在你启动SQL Server 管理环境之后,系统会直接连接分析服务的服务器,并能马上完成请求连接的操作。

例如:如果你处理一个Cube或者维度,系统内部将使用受控的API,也被称为分析管理对象(Analysis Management Objects ,AMO),通过这些对象来查找信息以及请求管理功能,例如:对象处理。一些操作是通过AMO来实现的,另外一些是采用XMLA脚本来实现,但是无论是那种方法,都是依靠运行的分析服务服务器来完成的。由于分析服务支持并发访问,系统保留了结构上锁的特性,用来避免在多个操作并发的时候产生的冲突,例如:当某个维度正在被一个操作处理时,这个结构能够阻止试图删除这个维度的操作。

SQL Server 管理环境(Management Studio)是作为一个管理应用程序而被设计的。它并不是一个开发环境。它允许你用它来浏览分析服务(Analysis Services)服务器和执行各种相关的操作活动,例如执行备份和恢复;同步服务器;配置服务器等。当SQL Server管理环境完成基本对象管理时,例如更改少量的属性或者删除对象,它就需要依靠其它的程序来设计和配置分析服务对象。

BI Development Studio 项目模式 (默认模式)
想要设计和实现 Analysis Services 数据库的开发人员和数据库管理员可以利用BI Development Studio 与 Analysis Services 相合作。BI Development Studio 是运用 Microsoft Visual Studio® shell 构建而成的。利用BI Development Studio 完成操作与利用其他SQL Server 工具完成操作非常类似(例如创建一个集成服务包或者产生一个服务报告)。 Visual Studio shell 的一个原则就是开发是一个反复编辑,构建,配置的迭代过程。

对于Analysis Services来说,这就意味着你一旦开始了一个Analysis Services项目,你便与Analysis Services服务器分离开来。起初,你通过如下任意方式构建项目:1)从相关资源中创建维度,cube和其他对象,为Analysis Services server创建项目。2)从服务器中获取一个已有的Analysis Services数据库,并在库中创建项目。一旦项目被创建,它便与Analysis Services服务器分离开来(并且和其存在的数据库也分离开来)。你可以在飞机中或是家中利用便携式电脑脱机的获取项目。仅当你重新与Analysis Services服务器连接。 

当开发项目时,BI Development Studio将检查对象在项目中和Analysis Services服务器中的不同。这些不同点用于同步项目与Analysis Services服务器。这就意味着创建了在脱机状态下创建的新对象,编辑了在脱机状态下改变的属性,删除了在项目中没有但是在Analysis Services服务器中存在的对象。

这是一个非常强大的范例。开发人员开发一个应用程序,然后进行编译和配置。从创建开始,项目可以脱机的存在于开发人员的工作站中,在工作站里项目可以被编辑,开发,然后被重新编译,配置。这也是用于Analysis Services项目的同样范例。

如何确保两个开发人员不对同一段代码冲突编辑?BI Development Studio运用了一个资源控制系统。任何人在通过相同的资源控制系统工作时,两个开发人员就不可能同时操作同一段代码了。BI Development Studio项目中的文件也是用了上述的方法保证避免冲突。这种方法也应用于项目子文件,例如组成项目的维度和cube正如组成应用程序的C#程序源文件一样。 

BI Development Studio直接联机模式
你可能认为有了这两样工具所有事情都可以做到了:操作人员使用的SQL Server Management Studio和开发人员使用的BI Development Studio。然而,在有些环境下,数据库管理员和操作员需要BI Development Studio的功能去完成他们的工作。事情就是这样的,例如,当你需要知道哪个cube有着什么样的尺寸,或者需要知道完整计划时。为了实现这个目的,BI Development Studio提供了一个直接联机模式。进入此模式需要在启动BI Development Studio后,在File菜单中选择Open选项,然后选择Analysis Services database。

在这种模式下,你不能使用脱机的项目。相反,你将直接联接到Analysis Services服务器上。如果你创建了一个分区,cube,或者维度时,你将直接创建,更新,删除对象。你将工作在运行的数据库中。在这里没有脱机编辑因此也就没有开发和迁入的基础文件。

如何陷入麻烦
很明显你能注意到这个问题。开发者利用资源控制系统保证工程文件在同一时间内保持一致。运用SQL Server Management Studio和直接联机模式下BI Development Studio的操作员依靠运行服务确保两个人不会同时进行相互矛盾的操作。这两种工作机制分别存在于自己的群体中。然而,他们却无法知道另一个群体做出的改变。运行中的服务不了解资源控制系统,资源控制系统也不了解运行中的服务。工程文件不能总是比较匹配运行的数据库。下面是几个这种麻烦发生的例子:
•        开发人员通过将一个现存的Analysis Services数据库引入到项目中的方式来创建一个项目。然后操作人员运用SQL Server Management Studio删除了数据库中的一个Cube。当开发人员配置项目时,cube有恢复了。这会产生一条如图1所示的消息:


图1:BI Development Studio检测到自最后一次开发后数据库被改变了。

我们注意到消息没有告诉开发人员哪个对象被改变了,仅仅告知不匹配的数据库版本。因为开发人员不知道改变了的对象是否重要,她或他能做的事情就是点击YES。结果cube就恢复了。
•        Analysis Services项目被保存在资源控制系统中。你在Analysis Services服务器中通过执行SQL Server 2005集成服务包中XMLA脚本创建了一个新的分区。例如,日常的SQL代理工作可能运行此包来处理引入的数据文件。当一个新的月份到来,此包为本月创建了一个新的分区。然后,开发人员在资源控制下改变了项目并配置项目。所有通过SQL Agent job创建的当月分区将消失。
•        运行的服务器系统崩溃并且丢失了一个磁盘驱动器。操作员将数据库恢复成为三个月前的状态,并且重新处理此数据库。开发人员配置一些QA要求的紧急改动(在资源控制下)时使得应用程序暂停。操作员认为应用程序停止是因为重新恢复备份被破坏。他们将数据库恢复到四个月前的状态。这时开发人员看到产品中没有他做的改变。因此开发人员有一次的配置了项目….因此有一次的停止了应用程序….随后操作员又将数据库恢复成为五个月前的状态。(你可以想象这种情况。)

如何解决这个问题…
这些事件的各种组合都可能发生。这将产生一些问题:
1.        如何检测这种问题的发生
2.        如何解决这种问题
检测到问题通常很简单。即使一个诸如修改一个对象属性这样的微小改变也会导致图1显示的错误。我们注意到仅仅是开发者被告知脱机项目文件的版本不再有效。除非开发人员告诉操作人员,否则操作人员并不知道他们在线的修改影响到了开发人员的工作。如果开发人员没有通知操作员并且开发人员继续配置他们的项目,即使数据库被修改,操作员看到的现象将是他们的修改来回反复存在和消失。

真正的挑战是如何解决这个问题。不幸的是没有一个机制自动的同步运行的Analysis Services数据库和脱机的Analysis Services项目。唯一的方法通过如下几个步骤来实现:
1.        重现将Analysis Services数据库引入到一个新项目中。
2.        利用引入功能重新创建所有文件
3.        利用资源控制系统迁出项目(以及他们的子文件)
4.        将新文件还原为迁出文件
5.        迁入新版本到资源控制系统。如果你能正确操作上述步骤,现在资源控制系统将包含所有事务的最新版本
6.        配置新项目,以让数据库版本号匹配。
另外一种方法是比较新引入项目文件和迁入资源控制系统的当前文件。一旦你发现了区别,逐一修改每个对象和属性以达到文件的匹配。你有效的做到了Analysis Services数据库和资源控制系统的人工同步。这种方法容易出错并且对于检测出所有差异和同步所有属性没有保证。
在同步过程中,无论是人工操作还是替换整个文件,操作员都不能在对在线系统做任何修改。此时的任意修改在最后的配置前都将被覆盖。所有的开发人员现在都必须从资源控制系统得到最新版本,或者迁出整个项目来更新人们本地的文件拷贝。
不管怎么来说,这个方法包括很多移动复制工作,这便很容易出错。如果你将要进行如此段描述的混合工作,你需要制定详细的能够确保开发人员和操作员协调合作的指导方针。

数据库设计
项目REAL Data Warehouse在一系列的多维Analysis Services数据库中执行,这些多维数据库称为:
•        REAL_Warehouse_V<n>(<n>代表数据的data-masked版本)是几千兆数据库版本
•        REAL_Warehouse_Development_V<n>是数据库的开发版。它包含维度成员的全部设置,但是每15个分区在5个存储器中。REAL开发小组使用它作为一个数据集(约15GB),每一个都能轻易的构建和测试。这种小规模的数据集能够让地理上分散的开发团队更好的共享内容。

•        REAL_Warehouse_Development_V<n>是数据库的一个样版。它包含了一个维度结构的子集和大量的真实信息。不管怎么说,它覆盖了很长的一段时间(52个星期长的数据),因此,它里面的所有数据是系统很好的一个Demo。它正是作为Project REAL系统的一部分,为外部发行而用的。这意味着你将有足够的结构化数据使得系统能够运转。他也是其它各种Project REAL的基础。

所有这些数据库有相同的对象和结构。每个数据库有单独的一个Cube,和11个维度以及4个度量组。

数据源和数据资源视图
数据源是你在Analysis Services建模活动的起点。对于REAL项目,我们将三个SQL Server 2005关系数据库整合成一个关系数据库管理系统,它被用于数据源,Cube和运用此系统的结构。

数据源
对于所有数据拥有单一的数据源是不够的。我们最终的目的是检测出Analysis Services和资源RDBMS之间的访问路径,当他们处于服务器的不同的域中时,或许他们直接还有防火墙隔着。因此,我们及早的做出了决定我们应该运用SQL Server标准安全而不是集成安全来访问RDBMS。

我们通了过Analysis Services创建了一个专用的SQL登录来进行访问。这个帐户姓名为REAL_User,密码为password。这并不能创建一个高安全性的环境,但是已经足够我们使用了。在SQL Server数据库中,这个注册用户仅被给予data reader权限。

如创建和使用此数据源部分一样,我们注意到一个有趣的SQL Server 2005 Analysis Services现象。这就是当数据源被创建时,数据源密码被内部加密(这就意味着密码没有以明文的形式存储)并被同时删除了。因此,无论何时我们制作一个数据库拷贝时(通过在SQL Management Studio中选择Scripting然后选择任务菜单的Create Script来完成),XMLA脚本中的数据源密码都被设置为空。实事上,我们无法利用执行脚本,拷贝粘贴或其他机制将密码拷贝到另一个对象中。不管我们怎样拷贝,系统总是提示密码丢失或错误的密码。

最佳实践:当在标准安全模式下工作时,记住你的密码。当移动对象时候,你将经常需要输入密码。

删除密码有优点也有缺点。它能防止盗窃密码行为。甚至管理员也无法通过拷贝对象来使用它。当第一次使用拷贝时,管理员必须重新输入密码。在第一次使用拷贝后,数据源上有个选项,用来提示密码被数据源内部存储(加密)并且每次必须重新输入密码数据源才能被打开。得到OLAP管理者权限的恶意的用户不能拷贝任意对象,在任意其他环境上下文中使用对象,也不能通过检查数据源来获得密码。

不幸的是,这将使得通过存储在资源控制系统中的脚本构建一个每晚或每周自动重启的系统变得很困难。这是因为存储在资源控制系统的对象没有包含有效的密码。如果你的开发工厂夜间运行,自动重启,那么数据源中构建的对象就不能被Analysis Services处理,直到你输入正确的密码。在你从资源控制系统中提取和重建好所有Analysis Services对象后,你必须在能够自动处理维度,属性,分区和其他对象前为数据源设置一个有效密码。这将承担了一个安全风险,因为,密码会被以明文形式设置。因此要小心如何设置密码以及如何控制需要读取这些程序用户的访问。

数据资源视图
我们为系统的用户创建了一个数据资源视图。数据资源视图是用于扩展对象的抽取层(关系表和视图),扩展的对象被数据源用于从被创建的Analysis Services对象中抽取对象集合。为了保持典型关系数据库的最佳做法,我们不在新表中创建任何对象,但是运用关系视图。

在数据资源视图中我们包含了全部的关系视图,这些视图用于创建维度,层和属性。我们没有为每个测量组实现包含关系视图-这对于每个测量组分区来说是最基本的。此模板没有包含任何数据-仅是分区表视图,查询绑定和其他对象如何恢复的定义。

最佳实践
如下将叙述多种最佳实践
•        在那些可能的地方,能够继续使用视图向分析服务(Analysis Services)提供一个高质量的星型/雪花(star / snowflake)模式
当数据资源视图允许DBA构建复杂结构时,他们不需要专用的空间为数据添加事务值。数据资源视图不能通过数据库,服务器,应用程序被共享,也不能通过SQL Server中BI组件(例如位于Analysis Services,整合服务,报告服务之间)被共享。如果你通过视图添加了事务消息,你最好通过所有的应用程序重新使用那项专门的技能。我们发现利用数据资源视图来扩展一个系统是两种情况下极好的决策。一种情况是当RDBMS不允许设计者创建或改变视图时,另一个是当事务消息与cube的多维属性有关并与关系对象无关并且重用也不重要时。
•        运用数据资源视图创建foreign key (FK)关系,此关系不存在于基础数据源中。
FK关系不存在于数据源中的原因有很多。例如,数据来源于数据仓库。对于数据仓库,缓解参考完整性约束这是很常见的甚至他们在数据模型中已知的情况下。这样做将加速大批量数据的处理,或者当运行在清除阶段时包含可疑数据。同样,如果数据源是个数据库产品,那么参考完成性约束将不会被公示,这是因为基本关系数据库不支持这些。例如,不同数据库中或是不同服务器中的表。数据库和服务器的参考完整性约束在SQL中不允许。然而,当Analysis Services 创建SQL命令从数据源中收集数据时,FK关系非常有用。幸运的是,数据资源视图被用于为Analysis Services添加FK关系,这超越了数据源本身的定义。
•        非常容易获得被携带离开的数据资源视图和创建过多的关系
如果你的数据已经包含在星型模式中,FK关系就不再需要了,认识到这点很重要。关系被典型的应用,因此Analysis Services知道如何构建基本SQL命令。关系不需要用于浏览和操作对象或查询中。在REAL项目数据库中,我们没有定义数据资源视图关系,我们的系统也构建的相当完善。
使用数据源视图扩展元数据(metadata)
通过使用数据源视图很直接也很容易扩展元数据。在Project REAL中,我们以下几种方法使用扩展的元数据。
•        我们使用扩展的元数据来创建在离散化分组中用于数据转换的计算列。例如,Item维度有一个为称为Publish Year的属性。不管怎么样,年份都具有一些分析的意义。如何区分一个出版于1934年的书和一本出版于1992年的书?一个用于分析更好的属性应该是自出版以来已经有多少年了。因此,我们在Item表中创建了如下图所示的计算列(使用数据源视图)。

ISNULL(DATEDIFF(yyyy,Publish_Year,GETDATE()),0)

这个使用标准SQL函数的语句,将出版的年份转换到一个变量,变量的值是从出版年到现在已经有多少年了。
分析服务支持自动离散变量(例如自从出版以来的年份)。使用数据挖掘运算规则,分析服务能将值存储到统计出来的有意义的分组中。在这个例子中,我们最后得到以下十个分组
-3 到1 年 (因为Item表中包含在未来3年后才能出版的书籍,因此-3是一个有效的值)
2 年
3 年
4 年
5 年
6-7 年
8-9 年
10-13 年
14-103 年
我们为以下属性使用了这种统计方法。



•        用大家知道的范围来离散化的分组(不仅仅是统计),我们使用了稍微有点异样的方法。在这里,我们使用Transact-SQL CASE语句硬编码的方式创建一个计算列。例如,在数据源视图Store中有一个被称为Age of Store的计算列。它使用Case语句来分析数据源中的“bucketize”属性(创建日期)。
CASE
  WHEN DATEDIFF(mm,open_date,GETDATE()) BETWEEN 0 AND 12 
THEN 'Less than a year old'
  WHEN DATEDIFF(mm,open_date,GETDATE()) BETWEEN 13 AND 24 
THEN '1 - 2 years old'
  WHEN DATEDIFF(mm,open_date,GETDATE()) BETWEEN 25 AND 60 
THEN '2 - 5 years old'
  WHEN DATEDIFF(mm,open_date,GETDATE()) BETWEEN 61 AND 120 
THEN '5 - 10 years old'
  WHEN DATEDIFF(mm,open_date,GETDATE()) > 121 
THEN 'Older than 10 years'
  ELSE 'Unknown'
END
尽管这个统计方法不需要硬编码,但它也不允许商业用户指定它们是如何被计算分组的。这里,我们能够将业务知识直接的嵌入到数据源视图中。

•        为了正确的对Age Of Store排序,我们创建了一个为称为Months SinceOpened的计算列。定义语句如下:
ISNULL(DATEDIFF(mm,open_date,GETDATE()),0)
然后我们将这两个列都添加到Store维度,并作为属性。我们再在Months Since Opened和Age of Store之间创建属性,然后再把Months Since Opened 的Order By属性的值设置成Key;然后把Age of Store的Order By属性设置成Attribute Key。这个配置允许能够按照Age of Store适当的排序(根据Months Since Opened),它也允许将两个属性都包含在查询中。
从数据源视图中忽略对象
尽管数据源视图已经经过有力的提取,但是仍有很多次,在数据源视图中包含了不改包含的对象。例如,你不应该在你的数据源视图中包含如下的对象。
•        没有需要的表和视图(尤其是对分割表)。如果一个表或者视图在维度中是没有用处的,或者只是作为一个度量组的模板表,那么就不要再包含它。因为这样做,只会让数据源视图更加混乱,并且难于导航。
•        系统不使用的业务对象表。例如,如果因为需要使用人员信息,数据源视图包含了人员数据源,然后添加Employee表,但是不做其它其它任何处理。请不要包含所有只是再人员应用程序中使用的其它的引用表和实体表。
•        其它应用程序使用的控制表。例如,在人员数据源中,你可能有一些用来控制文件或者调整ETL处理,以及更新人员应用系统数据流的表。请不要包含这些表。

修改数据源视图
在一些特定的情况下,你将需要修改数据源视图。例如,你可能需要将某个数据源表中列从integer类型修改成varchar类型,或者可能需要将varchar的大小从20字符调整到50字符。或者你可能需要修改维度定义,这些都会影响到Cube。

当你从数据源视图构建对象的时候,例如维度对象,然后将对象添加到Cube中,然后再在Cube中添加分割表,现有的元数据都会改变并影响到整个对象树。低级别的一些修改不代表这种修改会自动的带到更高的对象上。例如,假定你修改RDBMS维度表中一个列的数据类型。数据源视图不会做出自动的改变。数据源视图必须被刷新才能得到更新的结果。

同样地,如果数据源视图有所变化,基于这个数据源视图创建的对象不会自动地更新。如果一个维度或者Cube属性构建于一个列,然后你必须重新从数据源视图创建对象。实时上,你能猜到当你做出一个变化,你必须手动个根新更高级别地对象。如何让系统在一个改变地基础上,完成所有其它地改变。这里有一些指导:
•        如果只是简单地改变数据类型地大小,例如将一个数据库列从varchar(20)改成varchar(50),右键单击数据源视图的背景图,然后选择Refresh。这将更新整个数据源视图。那里可能还会有对象仍在使用旧的大小为20的值。对于这些在度量组中用来作为度量的列,编辑Cube并查看度量的数据类型和大小。对于那些被用来作为属性的列,编辑维度并改变相应的属性值。
•        如果是添加一个列,这样的改变,首先在数据源视图上单击Refresh。这将使得这个列是可用的,因此能够基于它去创建分析服务对象(也就是说维度中的属性;度量组中的度量)。
•        如果是删除一个列,这样的改变,当我们刷新数据源视图的时候所发生的事情取决于这个列是否被用来创建服务对象了。如果这个列没被用来创建其它的对象,在点击Refresh后,这个列就被删除了。否则,当你点击Refresh后,系统会提示你将删除一些对象(由于它们依赖于这个列)。
•        如果是添加或者删除一个表这样的改变,右键单击数据源视图,选择Add/Remove Tables。删除一个正在被分析服务的表,会带来一些分裂性的改变。在你删除一个表之前,首先是到Cube中更高级别的对象中。如果度量组使用了这个表,请删除这个度量组。如果是一个维度表,那就首先从所有Cube中移除这个维度,再删除这个维度。
一些增加性的改变能让你从方法学的角度来评估删除操作所带来的影响。如果你仅仅是从数据源视图中移除一个表,系统会告诉你更高级别的对象会被删除。(这可能包含很多使用这个表的对象。)一旦你点下Ok,表和指定的对象都将被删除。尽管这是一个简单的一步性操作,因为它不会让你去评估更远变化产生的影响,因此,最好还是严肃的、慢一点处理这个过程。
•        这种变化也有可能是逻辑结构上的变化而不是物理结构上的变化。例如,你可能会改变一个属性的键结构。物理数据源视图没有任何变化,但所有使用这个逻辑结构的对象都将被改变,要么重新创建这个对象要么通过刷新结果来更新对象。 

例如,这就发生在当你使用特定粒度Cube中的一个维度时,键结构被内置到Cube中。为了重置键结构,只需要将这种粒度的Cube改变到其它的属性,然后在将其重新设置到原先的属性。这样重构结构,新的键值定义就会被使用。当我们在Project REAL中不得不调整它时间维度的键集合时候,我们就遇到了这个问题。

当确定属性键唯一性的时候,同常的情况时创建一个键集合,而不是使用一个单独的列。在Project REAL模式早先的版本中,我们有一个更简单的时间维度,在Month属性上并没有添加唯一性约束(也就时1-12)。为了将Month属性键设置成唯一,我们在Month键上添加了Year列。当我们完成后,我们发现,我们无法再重新部署Cube。维度的构建没有任何错误,打开查看结构也是正确的,但当我们部署Cube的时候,就遇到了错误。这是因为Cube的时间维度只有一个列来作为Month属性的键,而再新的维度键上却有两个列。为了修复这个问题,我们需要再Cube的维度中同步这个Month属性。

为了完成同步,我们改变了Cube的粒度,从Time.Day修改成Time.Week,然后保存Cube,然后再重新将它设置为Time.Day。这种内置维度的重置,也重置了键结果,因此,它的Month属性的键也有两个列。问题就得到了修复。

结论
总的来说,数据源视图在分析服务中有两个重要的角色。

首先,它们是在分析服务使用对象和数据源之间一个抽象的层。这允许你创建类似命名查询和计算列这样的对象,这些对象也能在数据源中直接创建(例如,关系型视图)。这很重要,因为分析服务的管理员可能没有必要的权限去改变源系统上的元数据。例如,源系统可能是一个保留了主要的私人信息的组织级的SAP系统。作为组织的资源,管理分析服务服务器的DBA可能没有权限在这个源系统中实现添加、移除或者改变视图这些操作。但如果把这些改变放到数据源视图中,DBA就能从一个抽象的层获得好处,而不必再去改变源系统上任何信息。
数据源视图允许你在那些不在物理数据库上或者不可能位于不同的数据库上的表和视图之间创建关联。例如,你不能在两个存储在不同数据库上的表创建外部关键字约束。这个关联对于那些从3NF或者OLTP数据库构建的维度是很重要的。

不要让数据源视图失去自控能力。毕竟它们只是一个工具,而不是一个万能药。如果你开发了一个很好的多维度设计,你可能会发现它们不仅仅是很有趣的工具。

维度(dimensions)
在Project REAL中,我们有大量的、复杂的维度。这也是带我们到这个特殊应用程序的内容之一。这有大量的分析是基于厂商所扮演的角色。这里有许多半可加性的度量,例如库存数量以及其它类型的库存数据。这种多维度设计对于那些已经开发或者正在维护零售数据库的人员是非常熟悉的。

维度键
维度包含的内容主要是用来过虑或者考虑真实表的各种度量。Cube中的维度都会映射到一个关系型的维度表。
逻辑模式有两种类型的键:代理键(Surrogate keys)或者业务键。代理键被用来表示表之间的内部关系。业务键(Business keys,有时也称为natural keys)是为了从业务本身中标识一个实体。因此,例如,尽管厂商被代理键(使用一个标识的属性,例如1-n)指定的时候,但在外部世界,它们自然键(natural keys)是一个厂商编号-例如,厂商#7233703。对于真实的表,ETL过程都会将业务键映射到代理键,因此,当记录被暴露到分析服务的时候,事务就已经发生。

在我们的案例中,代理键被用来跟踪第二种类型缓慢变化维度。你将发现,所有的维度键属性都使用了代理键列。我们在维度键属性上不使用自然业务键,因为多个第二种变化类型记录可能会有相同的业务键。尽管各种类型和缓慢变化维度的使用已经超出了本文的范围,但数据模型本身还是在推断的成员中使用了第一种类型和第二种类型缓慢变化维度用来插入,可以参见Project REAL: Business Intelligence ETL Design Practices 白皮书。我们也推荐在 http://search.barnesandnoble.com/ booksearch/isbnInquiry.asp?isbn=0471200247网站上的Ralph Kimball的书籍《The Data Warehouse Toolkit, Wiley, 2nd edition》

层次(hierarchies)
尽管维度在报表中给出了度量的上下文和意思,但终端用户实际使用的分析对象是层次(hierarchies)。SQL Server 2005分析服务中,提供了两种类型的层次:属性层次(attribute hierarchies)和用户定义层次(user-defined hierarchies)。

在层次中是各个级别的集合。层次中每个Drilldown就是一个级别。例如Time层次中包含Year、Quarter、Month、Week和Day几个级别。在Book层次中(Project REAL中还用Item来表示)有Type、Subject、Category、SubCategory和Item级别。

报告层次(Reporting hierarchies)
第一个用户定义层次类型是报告层次。这个层次仅仅是用来报告的。潜在的数据并不支持各个级别上的关联信息。例如,我们有一个报告层次被设置成ALL->Author->Item。这样报告的目的仅仅是因为一个Item能够决定一本书,而其它的却不行。在层次中将作者放到Item前面,将产生一个多对多的关系。

自然层次(Natural hierarchies)
另外一种层次类型是自然层次,也被称为强层次(strong hierarchy)。在自然层次中,层次中的数据和其它的层次都有一个多对一的关系。日上 滚到周;周上滚到月;月上滚到季;季上滚到年。这将允许系统能够预先计算一个上滚动作或者是集合,例如为获得根据City的Store Sale的子集,然后根据City计算State;根据State计算Region;根据Region计算国家(这些求和都是基于层次的)。你能够重新打破或者再细分这些自然层次,因为每个成员都有且只有一个父亲。

自然用户定义层次不是SQL Server 2005新带的属性。它们在分析服务的早先版本中就存在。新的在于一种报高层次,它们是使用属性层次来构建的。

属性层次(Attribute hierarchies)
属性层次是SQL Server 2005中一个新的层次类型。它是基于维度表中的属性或者列。本质上任何数据库中的列都能成为维度的属性。当一个属性被定义到一个维度,一个属性层次就生成了。这意味着,如果时间维度表有一个Holiaday列,它只使用0或者1来表示某天是否是假期,然后你能够基于这个列创建一个Holiday属性层次。属性层次是平直的(Flat)。当一个层次只有两个级别的时候,我们称它为平直的。这两个级别是:所有的级别(把属性的所有值都加起来得到一个总的值);另外一个就是它自己。由于Holiday作为一个在用户定义层次中的独立的层次存在并使用,因此终端用户能够通过Holiday实现销售情况的分析。SQL Server 2000分析服务中有一个类似的概念,叫做虚拟维度(virtual dimension)。尽管使用虚拟维度,你能够基于每个成员属性创建一个维度,但虚拟维度在范围和伸缩性上都有很大的局限性。

基于层次系统(hierarchie-based systems)和基于属性系统(attribute-based systems)的对比
这是两个SQL Server 发布版本重要的、基础性的区别。

SQL Server 2000分析服务是一个基于层次的系统。内部结构都导向层次或者级别。这包括了,像集合,是级别的一个捆绑,每个都针对一个维度;像虚拟维度,将成员属性提升为维度。一个维度智能有一个层次。多层次是一个命名惯例。两个时间层次,例如Time.Calendar 和Time.Fiscal,看上去,它们都和Time相关,但在内部,这是两个不同的维度,只是恰好它们的名字上都有Time。一个名称为Product的维度也有可能是名称为Product的层次。在维度和层次之间没有严格的差别。

SQL Server 2005 分析服务是一个基于属性的系统。属性是构建对象的基础。集合是捆绑属性的求和。默认情况下,属性层次会自动的为属性创建。一个维度能有多个层次。在一个时间维度中,Time.Calendar和Time.Fiscal是两个层次(Calendar和Fiscal)。用户定义层次(例如Calendar和Fiscal)纯粹的用来导航实体。它们存在不仅仅是为了辅助属性的组织。你马上将会看到,这样的概念将在整个文章中被反复的出现。

维度中使用了如此多的逻辑结构。现在,让我们来看看维度的一些物理特性。在这里,我们首先讨论它们使用的内存。

分析服务2005中的维度缓存
SQL Server 2000和SQL Server 2005各自的分析服务在处理维度成员时,有很大的不同。在SQL Server 2000中,在启动的时候,所有数据库中的所有维度成员都需要被加载到服务器的地址空间上。这种情况下,内存就不能为其它程序提供很好的服务,数据缓存也将超出维度的内存。这样局限性就很大。这意味着,在一个32位的系统上(只有3GB的虚拟地址空间,但分析服务无法意识到这点),你能够具有的所有维度成员最大的数目也就几百万而已。如果你限制你成员属性的数量,并且保持这些属性很短的名称,这样你才可能达到3到4百万个成员。只要超出这个限制,你就不得不使用64位的服务器,以得到更大的虚拟地址空间。这是因为就Item维度就大概包含了七百万个成员。Customer维度大约有5百万条记录。这已经大大超出SQL Server 2000分析服务在32位系统上的承受力。

在SQL Server 2005种,分析服务使用一个动态的维度缓存,并不是将所有的成员都静态的映射到内存中。系统会在成员被要求的时候才把它们加载到内存中。在其它维度成员被请求的时候,会释放先前的成员。我们成功的在32位硬件和64位硬件上构建了整个Project REAL系统(事实上,存在这个系统的很多个版本)。并且对于这种大型系统,在32位系统上也能良好的运转。

我们也发现了那些不能构建到32位系统上的维度。但这里的上限跟SQL Server 2000的上限比,那就要大的多了。这主要取决于用来处理维度键属性的属性层次的hash表。当你使用太多的属性(或者如果属性的规模太大),然后最终超出了可用的内存,这个维度就不能被处理了。

对于维度来说,恰好落到不能被构建的界限里面是因为它们太大以至于不能加载到内存上,下面有两种方法减少需要的内存,来处理它们。

首先,确保所有的属性都确实需要被用来进行分析。如果不是必须的,从维度中去除它们。这能使得Hash表要求的空间更小。

第二,使用级联的属性关系,这样能够最少化属性的数量,因为它们都直接依赖于键。每个属性必须直接地或者间接地关联到一个维度地键。当你第一次创建维度地时候,你将注意到,所有属性都直接地关联到一个键。这也是键属性的特征之一,所有属性都能关联到它。然而,作为为维度定义的自然用户定义层次,一些属性会生成额外的关联。这样,它们既直接关联到键,也通过自然层次,间接的关联到键。例如,如果你清楚Time维度中的Day,你也将知道Year(Year直接被Day暗示)。同时,Day也暗示了Week、也暗示了Month、也暗示Quarter、也暗示了年。因而,在定义自然的用户定义层次后,你就能把Week、Month、Quarter和Year从Day的直接关联中去掉。如果间接的关联存在,就删除直接的关联。

依赖的属性能被移除,因此它们不再直接依赖于键,但它们通过在自然层次中通过属性关联能够间接的关联到键。并且,它们也能从维度的键属性中移除。这是一个很好的例子,详细参见图2。


图2:一个时间维度的良好设计
对比如何将属性关联定义到calendar属性上和如何将属性关联定义到fiscal属性上。绝大部分calendar属性不是直接关联的键属性(Day)的;仅仅只有Week。相反,绝大部分calendar属性能够向上级联到calendar自然层次。Fiscal属性关系也是这样一种情况,只是属性都是直接关联到键属性上的。

这个方法认为calendar属性应该是首选的方法。如果你定义了自然的用户定义层次,或者其它具有级联效果的属性关系,你就必须将直接的关联移除掉。这里有两个原因。首先是这样消耗更少的内存。第二是当集合设计向导(Aggregation Design Wizard)运行的时候,多余的直接关联将导致更慢的集合设计。

属性关联
在图2种,标记了两个属性之间定义的关联。标记了日和周、周和月、月和季以及季和年之间的关联。当你这么定义的时候,这代表了什么呢?有趣的是,这意味着那里有一种多对一的层次关系。只要给定一个周,你就知道有也只有一个月包含这个周;给定一个月,你知道有也只有一个季包含这个月;同样,给定一个季,你就知道有也只有一个年包含这个月。基于此,系统能优化它的计算,因此它能够向上滚动,体现出这种层次关系。

最佳实践:多花点时间用于维度的设计,在维度种捕获这种属性关系
重点:如果你想设计有效的集合;如果你想通过计算引擎,实现有效的计算;或者你想验证MDX时间函数的结果,你就必须定义属性之间的关联。

在SQL Server 2000分析服务中这种基于层次(仅仅支持自然层次)的性质,集合就是根据层次来设计的。在SQL Server 2005分析服务中,集合可以和属性绑定。用户定义的层次是不能使用的。存储设计向导(Storage Design Wizard)使用属性关联来决定什么时候绑定属性向上滚动,这是很有用的(因而,需要为那些属性设计集合)。没有关联,任何一个属性都和其它的属性一样重要,因此,存储向导会简单的忽略属性,并为维度使用All级别。因此,如果你想要设计一个有效的集合,你必须定义属性关联。没有关联,系统仍然会返回适当的数目,但必须在运行的时候才能得到计算的值。这样,集合就没有用了。

当计算复杂的MDX表达式的时候,规则引擎也会用到属性关联。没有属性关联,例如non-empty交叉连接这样的操作不能被优化或者有效的处理。因此,如果你想从规则引擎有效的执行运行时计算,你也必须定义属性关联。
最后,在时间维度中,属性关联也很重要。许多和时间相关的MDX函数只有当属性关联和属性类型被设置正确的时候,才能返回有效的结果。一般地,你能依靠商业时间智能向导(BI Time Intelligence Wizard)来设置适当的结构和关联。无论如何,在你手工的定义时间维度以及使用MDX时间函数的时候,如果你想获得有效的结果,你必须在你的时间维度中定义属性关联。

有两种类型的属性关联。第一种关联类型,也就是到目前为止我们一直在讨论的,当需要设计集合的时候,系统用来表达在哪里向上滚动的关联。如果读者对SQL Server 2000分析服务比较熟悉,他将会注意到,同时还存在另外一种关联类型。这就是类型的成员属性。

例如,在Project REAL的逻辑模式中,我们有一些属性,例如地方经理的名字以及他(她)的电话号码。这些属性被我们分别规格化到Store维度表中。这些属性由于不同的显示目的或者不同的分析要求,因此都是各不相同的,例如地方、地区和仓库等。一些分析是基于地区的,而不是基于经理的电话号码的。当经理名字和电话号码不必用于分析,我们就可以将它们关联到地区。如果你知道经理的名字或者电话号码,然后就将自动的获得经理所在的地区。因而,在这两个属性之间表达了一种关联。然而这种关联对于分析是没有用处的,但对于终端客户工具是有帮助的。因此将这种成员属性表达为关联,必须在适当的位置标识这种关联,以至于当终端用户右键单击成员的时候,客户端工具能够显示成员属性的列表。

总的来讲,为了确保你设计和实现一个能正常工作的系统,就需要指定属性关联。否则,将会带来隐患。

键的唯一性
在维度中,SQL Serveer 2005需要将一个属性标识为键属性。这个键必须是唯一的。当系统处理维度的时候,它会要求你确保这种唯一性。这对于熟悉SQL Server 2000分析服务的管理员而言,是一个巨大的挑战。
SQL Sever 2000分析服务基于层次的特性允许DBA以多种方法表示键的唯一性。整个维度中的成员键都是成唯一的。例如,在一个维度的所有成员中,只有一个成员的键值为#42。或者,唯一性也能设置到一个级别。例如,Subject级别可能带有一个键值为#42的成员,但Item级别可能也有一个键值为#42的成员。或者唯一性也能够被关闭。在这种情况下,可能会有键值为#42的多个成员。仅有的约束是键值相同的两个成员不会是相同的父亲。系统内部实际发生的是,对于一个仅有一个层次的维度,即使你没有指定唯一的键,它也会创建一个唯一的键。

在SQL Server 2005分析服务中,一个维度可以包含多个层次。或者它可以不包含用户定义层次而只包含属性层次。这对于键的唯一性意味着什么呢?由于一个属性在没有其它结构化层次情况下,必须能够标识自己,例如一个平直的属性层次,键值#42意味着什么?最终,它表示这个键值是一个真实的键值。更确切的说,它必须唯一的表示一个属性。

除了键属性的唯一性,系统也考虑了其它属性的唯一性。当然这不是强制性的。如果我们不设置维度,确保属性键的唯一性,会带来预想不到的结果。

最佳实践(必须的):你必须总是确保属性键的唯一性。

首先,我们将想你解释如何为一个属性指定一个唯一的键,然后我们将想你阐述如果你指定错误,将发生什么事情?

假定你正在为你的项目(跟我们的Project REAL类似)创建一个标准的时间维度。作为维度中的一个属性,考虑以下Month列。它包含了从1到12的整数。一般你会设置如下:1 = 一月;
2 = 二月;……12 = 十二月。表面上,这看上去已经满足了唯一性的要求。但是拿2003年1月和2005年的一月比会怎么样呢?实际上,1…12不能作为键。键应该是年份和月份的一个绑定。对于一个关系型专家来讲,这不是一个新的概念。这只是一个主键和链接键。然而,对于一些熟悉SQL Server 2000分析服务的人来数,这是一个新的想法。在SQL Server 2000中,你能够在一个级别上设置唯一性,然后就不在关注它。在SQL Server 2005中,我们需要改掉这种老习惯。

幸好,指定一个唯一键是很容易的。简单的考虑以下属性的键属性。你将发现除了指定一个列,你也能够指定一个列的集合。集合中的每个列都提供了其唯一性(就像你指定链接键一样)。对于Month键,我们需要创建一个Month和Year列组成的集合。如图3所示。



让我们看看在这些变化前后发生了什么变化。

图4表示表示了当你使用的是没有唯一性约束的Quarter、Month和Week时,Project REAL的Time.Calendar的层次是什么样的。在下面的RDBMS中,键的范围分别是(1…4)、(1…12)、(1…52)。问题在于,在整个维度中,这些键值不是唯一的。例如,你如何区别2001年1月和2002年1月;或者如何区别2003年Q2季度和2004年Q2季度?为了使得键是唯一的,你需要用Year创建一个链接键。因此,Quarter的键应该是(Year,Quarter);Month的键应该是(Year, Month);Week的键应该是(Year, Week)。在这种情况下,我们没有创建链接键。你可以看到如图4所示的结果:年没有季节;在年中错误的季节;以及其它不准确的结果。


图5展示了当我们给Quarter、Month和Week键分别加上Calendar_Year_ID链接键后成为键集合的情况。现在的结果是正确的。



考虑一下对话框中行的数目也是一件有趣的事情。在我们用Year创建链接键之前,Month属性层次返回了13条记录。这就是当我们根据一个未知成员的月键,使用SELECT DISTINCT,你期望得到的结果。当我们添加了Year链接键后,新的处理会返回219条记录,因为SELECT DISTINCT语句中包括了年。

以下是几个注释。首先,如果你使用Project REAL提供的一个相同的数据库,执行这个练习,在维度处理过程中,不会产生任何错误(警告或致命的错误)。你必须扫描你的维度,并留意成员没有出现在预定位置的情况。
记录键的唯一性被用于约束相关的属性。如果你没有指定相关的属性,那所有的属性都被关联到键。由于键必须是唯一的,那所有的都没有问题。然而,当你开始指定相关的属性,你大概能说出关于属性的一些事情。你会说,这个键是唯一的。注意在前面的例子中,当我们发现键不唯一而带来问题的时候,就是发现相关的属性了。
如果我们不能再生成唯一键,我们智能选择移去属性相关性。我们这么做之后,属性就智能直接的关联到键属性,键属性要求是唯一的。没有相关的属性使得产生一个高质量的集合设计成为一件不可能的事情。这也是分析服务中的对于“键”你最后应该注意的地方。最后再强调一样,一定要确保在整个维度中,所有你设计处理的键都应该是唯一的。

最佳实践:总是扫描你的维度,确保它们包含你预期的广泛的、甚至是分布的成员。
如果你看到一个专注于分布式的,然后发生了一些不可能的事情。要么就是唯一键没有标识出潜在的属性或者层次的顺序不准确。例如,你疏忽的指定了Year、Month、Quarter而不是Year、Quarter、Month。上述两种情况都会导致不正常的层次,但在处理过程中,不会有任何提示。

如果你打算定义一个属性关系,它们必须在数据上基于有效的模式。属性关联对于设计和实现一个高性能的系统是非常重要的。如果一个键结果导航系统执行一个错误的上滚操作会发生什么呢?例如,如果你在一个正常层次中颠倒了两个级别,会发生什么呢?

假定你正在定义一个Store正常层次的顺序是(All、Region、District、City、Store),实际上定义的却是(All、District、Region、City、Store)。正常的顺序是由属性关联来构建的。在这种情况下,这种单方面的被用于构建一个属性关联就不在被数据所支持。一种情况可能是一个Region能上滚到许多个District。然而这种计算是错误的。在运行时,数据被计算了两次,并且在层次上也是错误的。系统不能正常运行并返回错误的结果。所以,在定义属性关联的时候尤需注意,因此即使定义错误也不会返回任何错误。

最佳实践:如果你告诉系统属性是关联的,则它们必须是关联的。
数据必须支持关联。另外,键的唯一性必须允许这些关联能够被执行。
这就带来一个有趣的问题。如果你只是没有定义相关的属性,将发生什么?令人惊讶的是,一个有效层次返回了一个正确地结果,如图6所示。



图6所示的层次看上去是有效的。当你查询一个系统,数目都是正确的。问题在于,没有相关的属性,系统无法意识到属性之间重要的关系。这种关系标识一个上滚是能够在层次上预先计算好的(SQL Server 2000分析服务使用集合达到这个目的)。相反,系统不会在查询计算的时候使用它的运行时来完成上滚。由于没有设计集合,因此你没有告诉系统层次里面的属性是相关的。所以,你得到一个清晰的层次并很好的列举了层次,但是你不能使用预先计算的集合用来计算子集,因此性能收到了影响。

将虚拟维度转换成属性层次  
不幸的是,在我们的Project REAL中,我们不能包含我们在转换到SQL Server 2005之前在SQL Server 2000分析服务中设计的文档。相比于最终的设计,原先的设计要更加简单一些。现在差不多有一打的维度被去掉了。取而代之的是属性层次,绝大部分都是在Item维度中。例如,原先的系统携带了五个虚拟的维度,这些维度是在Item维度中,基于厂商关联建立起来的。 因此,在原先的设计中,都是用维度来针对Source Vendor,Return Vendor、Purchase Vendor等。那么在使用SQL Server 2005 的REAL的最终设计中,它们分别被Item. Source Vendor, Item.Return Vendor等属性层次所取代。在原先的设计中,还包含了一个Department正规维度(这个维度构建于一个Item维度的视图)。在最终的设计方案中,也被Item.Department 属性层次所取代。

最佳实践:将SQL Server 2000分析服务中的虚拟维度转换成属性层次
如果一个虚拟维度超过一个级别,那么能使用相关的属性作为级别,把它转换成一个用户定义层次。迁移向导(Migration Wizard)将帮你自动的完成这个工作。然而,当你手动的迁移或者在SQL Server 2005中重新设计的时候,你都应该意识到这些自动的转换。如果在虚拟维度总,仅有一个简单的级别,那么可以直接从数据模型中(和应用程序代码中)直接删除这个虚拟维度,直接使用属性关联即可。当你在考虑你的2005设计的时候,需要重新考虑每一个维度,并询问自己是否能将这个实体作为其它维度的属性?如果确实是这样,就可以用属性层次来代替。这能够降低系统的复杂性,对于终端用户也具有更多的意义。这些属性层次都揭露了原来的维度类型,并且这样做能增加一些对潜在的多维度设计的理解。

例如,原来Project REAL的设计中包含一个被称为Department的虚拟维度。它标识书籍能在那些仓库部门(例如硬皮或者软皮书籍)购买到。Department虚拟维度是从Item维度的一个成员属性上获得的,我们将它转化为Item维度中的一个属性层次。因而,终端客户能够清晰的看到相关联的Item,而不是Stores或者其它的维度。

可能的命名冲突
在同用户定义层次一起工作的时候,你可能会遇到命名上的冲突。这是因为用户定义的层次和属性层次一样共享了一样的命名空间。在SQL Server 2000分析服务中,有两种类型的名称:
维度/层次名称和级别(Level)名称。在分析服务2005中,有三种类型的名称空间:维度、用户定义层次和属性层次。因为用户定义层次和属性层次有相同的命名空间,因此就产生了潜在的命名冲突。

例如,你已经有一个名称为Buyer的维度。由于很多前端工具只显示层次的名称,所以你可能会创建其它名称为Buyer的层次。在分析服务2000中,你可以这么做。现在的挑战在于,如果你创建了一个名称为Buyer的层次,你将不能再创建一个名称为Buyer的属性层次。在Project REAL中,我们把属性层次重新命名为Buyer Name。如图7所示,所有相关的对象都必须唯一的被命名。



你不能在将一个属性层次命名为Return Vendor,也不能将一个用户定义层次命名为Return Vendor。因而在我们的设计中,我们扩展了在SQL Server 2000分析服务中使用的典型命名转换。在复杂的情形下,在名称经常被重用到的地方,我们用“By <name>”来命名用户定义层次(name代表了在用户定义层次中整备分析的属性)。对于这个对则也有一个例外。存在一些知名的关系,我们不必再做出澄清。例如Time.Calendar和$12.50。“By <name>”这个规则不是很适用。Time.By Calendar和Time.By Fiscal 看上去很不正常。但是对于那些用户定义层次和属性层次有相同名称的情况而言,命名转换是一个很有用的窍门。

将关系表中的列提升为多维度设计中的属性
每当我们检查Project REAL多维度设计的时候,我们经常问我们自己,是否需要在数据源视图的维度表中包含一个特殊的关系列作为一个属性视图。我们把这个过程称为提升(Promoting)列。



例如,在数据源视图的维度表中,一个Item维度有超过144个可用的列。为所有的这些列创建属性并不能很有效的利用资源,因为一部分列在分析中从来没有被用到。最后,我们决定使用其中的44个列作为维度中的属性。
一个有趣的设计问题是是否需要将维度表中的所有列都应改添加(或者提升)到一个属性层次中。默认情况下,维度向导(Dimension Wizard)能够完成这项工作。它会将所有的列移动到一个属性层次。你不得不手动地把某些列从属性层次中去掉或者防止被提升(Promoting)。无论是不提升一个列使其成为属性还是依赖于关系型数据源的复杂性和丰富性,都是一个很好的选择。

我们体传了一些指导方针,帮助你确定什么时候将一个列提升为属性。你会发现这些信息非常有用。
•        首先,确定你是否需要对这个列进行分析。属性层次是一个最基本的方法,帮助终端用户完成分析。它们使用将它们选择的属性层次作为对象使用,点击或者拖拉,区分或者转动。如果一个列不是属性,它们将不能被操作或者分析。

统一空间模型(Unified Dimensional Model ,UDM)的真正力量在于它采取了一个丰富的属性层次集,能够帮助用户完成数据分析。这种分析可以使用预定义的对象,例如用户定义层次或者那些可以完成特殊操作的对象。属性层次对于特殊分析是很有用的。例如,你可能想分析比较某个地区精装书和简装书销售情况。用户定义层次Store.ByGeography允许你一直向下钻,知道你想要的一个级别,也就是地方或者地区。另以方面,你能够将Item.Department属性层次拖到网格上,网格中包含了关于精装书和和简装书的数量情况。如果你没有将Department提升到属性,你将不能完成这样的操作。

如果你希望将来在一个列上面能执行分析,那么你应该将它提升为属性。例如,Item维度表包含了一个被称为Original EAN的列。这个分配给书本的第一个EAN值。(这个数目将来可能会变化)。我们决定,终端用户不会做基于它的分析,因此我们没有显示它。由于当前的EAN数目还没有达到要求的地步,因此我们要马上将它提升为维度的属性。但是,我们可能犯了一个错误。如果将来有用户想使用这个列用于分析的机会,我们将把它提升为属性。

在一个大表中,你不能提升任何列。当一个表中包含很多潜在的可提升列,需要决定提升哪一个是一项挑战性的工作。例如,在Project REAL的Item表中有超过144个列,它们都可以被提升为属性。让用户自己来跟踪这些信息显然是不合情理的。
•        如果一个属性只有在层次上下文中才有一点概念上的益处(换句话说,它基本上没有分析的潜力),可以将它提升为一个属性层次(这样你能够把它添加到一个用户定义层次上),但需要将它设置成隐藏。这不会干扰终端用户的视线。
例如,我们设置Buyer.Buyer Alpha 属性层次为隐藏。这个属性层次只是Buyer层次中购买人员的名字的第一个字符,只是起到了导航的作用。我们不希望终端用户在名字的第一个字母上做一些单机的分析。
下面是当不必将一个关系列提升为属性层次的应用实例。
•        如果维度中的一个列没有机能上的依赖关系(在3范式上下文中),那么就不用提升它。例如,Item维度表中大概有15个左右的列不依赖于Item。它们只是用来给这一些Item所代表的信息,规格化成列(也就是属性)。因为它们机能上不依赖于Item。因此,这些规格化的列不必在包含到Item的属性层次中。最终,我们从这些数据配置成我们想要的信息,但这部分并没有包含到Project REAL中。这只是因为包含在RDBMS表中的一个列并不一定要包含到多维度的数据模型中。
•        不用提升那些和维度没有仍和商业关联的列。在表中包含一些只是出于管理目的的列,并不是很少见。这些列并不描述实体(例如一本书或者仓库)。这种类型的列可能包含一个存储数据最后被更新的日期的列;或者包含一个是谁修改这个数据的列;或者创建记录的日期。由于它们和维度没有任何关联,因此,这些列不用被提升为属性。

和tinyint键不匹配的数据类型
在关系型设计中一个很出名的经验是你应该总是应该使用那些能够满足你正在使用对象范围要求的最小数据类型。如果你知道这点(出于商业原因),一个数值总是不会超出一个极限,就不要使用大的数据类型。这样做只会浪费存储空间。尽管,这总是一个很好的建议,但要提防在SQL Server 2005中,当我们处理tinyint的时候,可能会带来数据类型的不匹配。Tinyint键值作为byte类型(从1到255)保存。当数据源视图被创建后,如果tinyint键是一个标识列(可能是一个代理列),然后系统将把它转换为integer。因此维度的键是一个integer。但是,在你实际的表格中,智能保存tinyint的值,这可能会导致类型不匹配。

例如,在原先SQL Server 2000格式的Project REAL设计中,Department 维度是一个完整的维度表。Department 键是一个tinyint值(从1到13),包含了书本的类型,例如精装本或者软皮本。Department 键有一个Indentity属性,因此下一个值应该是14,然后是15等等。因为,往往是选择能够满足需求的最小数据类型,因此选择了tinyint。在这种情况下,原先的设计人员认为不会超过255个Department。自然地,实际表中有一个外部关键字,也是tinyint。当我们将设计前一到SQL Server 2005分析服务后,将导致数据类型的不匹配。

在这种情形下工作的时候,需要在数据源视图的维度表上创建一个计算列,需要显式的将键列转换成tinyint类型。然后,在维度的关键属性层次中舍弃原来的列而使用这个新列。尽管你也可以将实际表中的tinyint类型转成integer类型,但这会造成空间上的浪费。

尽管你会认为这可能是一个Bug(我们也这么认为过),事实上,这是由于早期使用Microsoft XML Core Services (MSXML)来进行开发造成到。在MSXML中,主张一种隐式的数据转换,能够将一个未知的数据类型转换成它们想要的数据类型(跟SQL Server RDBMS式不一样的)。在这里,tinyint是从SQL Server 早期遗留下来的数据类型,MSXML事实上直接将它转换成了integer类型。如果解决这个问题,有太多现存的MSXML代码需要修改,因此,我们不得不保留这种情况。

未知成员
决定一个系统如何处理未知值总是一个有趣的设计决定。在SQL Server 2000中,这个是很简单的,你只是需要创建一个你自己的应用程序级的未知成员。这包括在你的维度(Dimension)中添加一个未知成员以及在实际数据库表上添加一个ISNULL或者其它的关系型技术。在SQL Server 2005中,提供了一种新的技术,允许系统生成一个它自己的未知成员,并将它自动的赋给未知值。

在Project REAL中,我们采用这两种方案。在绝大部分NULL值上,我们创建了应用程序级的未知成员(我们称它为”missing”)。这种方案,在视图中的绝大部分工作都可以完成,也包括通过代理键值为0,来返回已丢失的信息。显然,当NULL值不使用0表示,而使用一些看上去就是异常的数据,这种方法会让系统看上去更完美。我们可以使用合理的“丢失”数据(我们预期的一些信息)来表示一些异常的无效数据(也就是无效的数据)。使用系统生成未知成员的问题是你不会察觉到逻辑上不合理的数据和无效、异常数据之间的区别。

最佳实践:在可能的地方,创建你自己的未知成员。使用系统生成的未知成员。

下面的代码是关于一个如何在关系型视图中如里未知成员的例子。
CREATE VIEW [dbo].[vTbl_Dim_Store] AS 
   SELECT store.SK_Store_ID
      ,store.Store_Num
      ,store.Order_Status
      ,store.Store_Desc
      ,COALESCE(store.Division_Num,0) as Merch_Div_Num
      ,store.Status
      ,COALESCE(store.Status_Desc,'Unknown') as Status_Desc
      ,store.Open_Date
      ,store.Close_Date
      ,store.Division_Num
      ,COALESCE(Store.Division,'Unknown') as Division
      ,store.Region_Num
      ,COALESCE(store.Region,'Unknown') as Region
      ,store.District_Num
      ,COALESCE(store.District,'Unknown') as District
      ,store.Market_Area_Num
      ,COALESCE(store.Market_Area,'Unknown') as Market_Area
      ,store.Market_Type
      ,store.Ad_Area_Num
      ,COALESCE(store.Ad_Area_Desc,'Unknown') as Ad_Area
      ,store.Center_Desc
      ,COALESCE(store.City,'Unknown') as City
      ,store.Zip_Code
      ,store.State
      ,store.Mgr_Name
        . . . 
FROM dbo.Tbl_Dim_Store store

COALESCE函数被用来将数据库中的NULL值转换到维度(dimension)中合理的未知成员。对于上文Transact-SQL代码范例中Merch_Div_Num 列,键值” 0”是对于未知成员的一个应用惯例。这个范例合理的清除了那些位置成员。我们有时会期望提供NULL值。我们会把这些NULL值转换成我们预定义好的、符合语义的内容。例如上文中的键值” 0”。

系统创建的未知成员是SQL Server 2005中的一个创新之处。在Project Real设计中,我们用它来处理那些丢失的客户。当它关掉的时候,这个专门的维度会包含大量的无效数据。在我们设计完整的系统后,我们注意到,因为无法根据代理值去查询相关的客户,因此大约有10%的销售数据是失败的。当它关掉的时候,这种情况是由于销售发生时间和客户在诚信卡系统中出现的时间之间的延迟造成的。在一些情况下,系统从Customer数据源得到关于新客户的数据反馈,需要花费一个月甚至更多时间。系统能够马上提供Sales数据反馈,但得到Customer数据反馈往往会有延迟。我们认为,这种反馈数据的不匹配并不是一种不正常的情况。你可能也会马上意识到这个问题。因此,为了跟踪这种类型的活动, 我们决定不调整整个ETL和分析服务(Analysis Services)处理。我们更恰当的定义了一个系统生成未知成员。然后我们为Store Sales部分修改了错误配置,因此一个外部关键字查询错误被转换成分配一个未知成员。
图9表示了如何配置一个维度。


图9:如何配置一个系统生成的未知成员。
图10表示我们如何在Store Sales部分改变错误配置。


图11表示当一个查询使用系统未知成员的时候,看上去是什么样的。



时间智能向导
过去当需要使用时间智能向导来创建新的时间维度时,我们遇到了一些挑战。SQL Server 2005 的分析服务(Analysis Services)是服务器端时间维度(dimension)。虽然,由于其容易使用的特性(只需点击几下就能得到时间维度),使用服务器端时间维度是很有诱惑力的,但我们并不推荐这种方法作为通用的实践方法。

最佳实践:可能创建单机时间维度表的地方
在处理复杂的时间情形时,拥有一张时间维度表会给你更好的伸缩性。
•        你能添加你自己的时间属性。例如,将某天指向周末还是普通的日子?某天时公司假日么?某天时季节内还是季节外?某天是在圣诞假期内么(对于很多零售商很重要)?
•        很容易标识和构建多重层次。例如,当两个公司合并的时候,新合并的公司需要运行两个不同的财务日历(每个对应一个公司)。
•        能够构建与众不同的层次。例如,一个公司的制造月总是从日历月的第一个周一开始,这可能会有一个与众不同的工作日编号系统。
•        在复杂情形下,业务模型可能要求完整的级别跳跃。例如,一个专门的日历可能有年、周、日;或者它可能只有年和日。
•        有可能根据需要来计算增加的成员。例如,一个代表逻辑上“今天”的值。在一些公司,预定结束日取决于客户的反馈数据。数据每天都在变,但公司需要一个逻辑上的今天,以至于它能够在预定结束前冻结预定。
•        一般情况下,我们建议在你的关系型设计中,在实体之间使用代理键(surrogate keys),作为最好的实践。然而,这也是这个实践可能没有意义的地方所在。如果你已经使用了一个时间戳或者其它时间的表示方法(例如,用整数20050321表示2005年3月21日),可能继续使用这种技术更有意义。在这个例子中有两点需要考虑。首先,确认你正在使用一个日期戳而不是日期时间戳(将时间从你的外部键中移去)。第二,你可以使用SQL Server RDBMS DATEPART 函数自动的从日期戳构建外部键值。

•        如果你的应用程序需要一个比日更加深入的细节,可以考虑将时间分成两个维度。一个维度记录到日为止的时间,另外一个维度记录日中的时间。

例如,你向跟踪没分钟的产品销售情况。乍看,你可能会创建一个如下所示的用户定义层次的维度。
年  季  月  周  日  时  分
假定就是按照这个维度来实现的,如果你手机五年的历史数据,那么在这个维度中将会有多少成员?这个结果是很吃惊的。这会产生2,675,795 个成员。不仅仅是一个巨大的数字,这种带有小时和分钟值的模型使得很难按照周或者月去处理信息。反过来,考虑使用如下的两个维度:
日期: 年  季  月  周  天 
时间: 期间  时  分
        (期间可以时下班时间, 早上, 中午, 下午或者晚上)
五年的历史数据成员会少很多(3,640个成员)。这个方法也支持更丰富的分析。你能够只关注早上的销售情况,你也可以为每月第一周做一个比较,比较早上和下午的销售情况(例如每月支付薪水那天的上午)。
有两种技术可以用来创建时间维度表。一种时使用标准的维度向导(Dimension Wizard)。使用向导创建所有的属性、层次和其它对象。然后再回过头来修改各个属性的类型,使它们匹配适当的时间语义。例如,
另外一种技术是使用时间智能向导(ime Intelligence Wizard)。为了启动这个向导,打开标准的维度向导,然后指出这是一个时间维度。时间智能向导就开始工作,并允许你输入指定时间的信息。如图12所示。



你会注意到这个向导少了一些东西。你可以输入许多时间属性,但是你没有机会同时输入一个键和一个成员名称。你必须选择输入的是键列还是名称列。

最佳实践:在时间维度向导中,为各个属性输入键列(非名称列),例如年、月、周。
选择键的好处在于,少后,你仅需要改变成员的名称。默认情况下,向导将把Order By属性设置到键上。因此,如果在这里输入一个键列,你稍后需要改变就仅仅是名称列。

在你运行完向导后,当我们开始涉及确定定义的时候,请牢记对成员键唯一性的要求。在这个时候,我们很容易去使用传统的键和名称。例如,你可能会把Q1,Q2,Q3,Q4作为名称或者键;或者你也可能像下面这种情况使用键值:用1代表1月,……,12代表12月。尽管数据库管理员都记得他们按照特定的顺序使用1…12作为月份的键值(否则4月有可能成为每年的第一个月),但我们并不能总是牢记这些顺序,因此值为Q2的季节或者值为4的月份并能够唯一的确定一个键。你经常需要回过头去,为成员键创建一个集合,并将年份添加到集合中以确定其唯一性。

不要忘记忘记给你创建的多层次对象创建属性关系。例如,在日和周之间、周和月之间、月和季之间以及季和年之间,创建一个属性关系。就像键的唯一性一样,如果你想要系统良好运行,这种关系也很重要。

一旦你确定了成员的名称,就需要确保时间层次上各属性键的唯一,需要建立一个属性关系用来支持你已经定义的多个层次,你也可以添加其它时间相关的属性,比如周末、假期和季节指示器等。

虽然时间看上去是一个简单的概念(毕竟,它只是一个时间戳而已),但你还需要在构建数据库表和分析服务对象上花费你大量的设计时间,以确保它们已被适当的设置。

度量组
Project REAL实现的关系型数据模型包括三张实际的表:Store Sales、Store Inventory、和Distribution Center Inventory。物理上,为处理大量的数据(例如,每周约1.4亿-2.0亿条存货记录),需要按周来分割这三张实体表。分割是很重要的,因为:
•        这能提供更好的性能。查询只会扫描覆盖某个时段的分割表。一般情况下,这些分割表越多,它们就越小,查询就会执行的更快。
•        更容易删除数据。简单的删除分割表,就能删除数据。你不必再重新处理任何Cube。正常情况下,从一个实际的表中删除数据,都需要重新处理Cube。
•        更容易实现起伏不定的周期。例如,假定一个系统需要保存最近三年有价值的历史数据。你可以按不同的周期来获得分割表,累积到36个月即可。这比从某个固定日期开始,要好很多。新的分割表按照每周或者每月不断的被创建。三年以前的分割表就能直接被删除。

一个对SQL Server 2000分析服务应用很熟练的用户会注意到Project REAL设计中一个有趣的事情:所有的度量组都是包含再一个单一的Cube中。度量组提供了一个在SQL Server 2000分析服务中被称为Cube的对象。一个Cube就是一个实际的表,它会连接到维度的一个子集,这个子集在数据库中可以按指定的粒度使用。一个真实表粒度是各种维度里面级别最低的。SQL Server 2000分析服务有一个称为虚拟Cube的特性,允许你将各不相同的Cube聚合到一个简单框架中。在SQL Server 2005分析服务中,一个Cube就是一个这样的简单框架。现在的度量组就是捕获各种粒度的维度子集。

如果你想使用一个虚拟的Cube,可以使用在多个Cube之间连接的度量组来创建虚拟Cube。这些连接的Cube(老式的Cube)每个都带有一个简单度量组。事实上,这就是分析服务迁移向导(Analysis Services Migration Wizard)所创建的内容。它这样作,也是想要把SQL Server 2000数据库分析服务和SQL Server 2005数据库分析服务中的对象数目和类型保持一致。

这种Metacube方法既有正面的意义,也带来了一些消极作用。通过这种方法,所有的事物都被丢到简单的Cube中。这种方法最重要的优点在于,由于构建Cube的方法,使得终端用户用户不必强加人为的界限,就可以去连接或者查询。终端用户看到的是度量值的集合。在用户如何查询Cube的基础上,系统可以动态的调整必要的度量组。

计算是类似的。你只需创建一个简单的Cube包含所有你提供的计算,系统就会根据它们做出自我调整。若要得到更多关于这种丰富的对象空间(所有的事物都在一个简单”罐子”中),可以查看AdventureWorksDW 分析服务数据库。这个数据库中包含了18个维度、154个属性层次、18个用户定义层次、超过100个计算以及9个度量组(每个粒度都不相同),并且所有对象都在一个Cube中,这太棒了。

无论如何,这种方法都会带来一些成本。最明显的程序是需要过渡很多对象。你需要客户端应用程序能够处理SQL Server 2005种的对象,例如显示文件夹或者透视图等。这些对象允许你将对象组织到不同的功能分类中,这样,用户能够更好的记住各对象可以应用的选项。

这个方法带来的第二个成本是执行一个完成的维度过程会对所有使用这个维度的度量组重置状态。这既包含了度量组,也包含了这些度量组的分割表。我们是在测试执行一个Vendor Type 维度(只包含五个成员)的过程中,意外的发现这点的。我们不得不回过头去,重新处理基于Sales 和Item Vendor度量组的153个分割表。显而易见,完成这个过程需要大量的时间。我们决定除非迫不得已,我们将不这么做。并且这可能导致更坏的结果。如果我们完成一个Measures 维度(只有一个成员)的过程,这将影响到所有的度量组。完成这个过程,会涉及2G的数据,需要在3天后才能得到结果。

如早先提到的那样,实际表中包含了以下三种信息:
•        实际表的粒度已经在它的维度中体现出来。每个维度都会有个外部键,用来指向在适当级别/属性的维度表。在Project REAL中,这些就是代理键(surrogate keys),这些键都是通过系统生成的,因此我们能实现第二种类型缓慢变化维度。这些代理键被连接的级别代表了这个维度的粒度。例如,时间维度键可能是Month。另外一个实际表可以是Day。对于其它的维度,这些键可以是Item和Store
•        并不是所有的维度都必须出现在度量组中。例如, Store Inventory和DC Inventory 度量组不必做任何基于Vendors的分析。因此,它们不必包括Vendor 和Vendor Type两个维度。
在Project REAL中,各个Cube的粒度如图13所示:



•        实际表包含的度量是我们需要在解决方案中报告的数据。在我们的案例中,Sales 实际表包含的度量有销售总计、销售数量、折扣数量和优惠券数量。
•        另外,实际表也可以包含一些附加的信息(被称为degenerate keys),但不会指向维度。但这些附加的信息自己可以包含维度。例如,对于Store Sales,实际表可以包含销售条目的注册数目。在Project REAL的实际表中,没有degenerate keys。
内部上,分析服务在每个度量组存储了大量的信息。下一个章节描述了跟度量组相关的信息子集(也是包含在设计细节中的)。

分割表
系统在分割表中存储实体表。一个分割表和每个度量组具有相同的结构。它包含相同的列,数据类型也完全一样。然而,分割表也可以包含数据的一个子集。例如,它可能只包含一星期的有效数据。

在这个章节中,除非有特别的说明,否则都认为分割表保持Week的级别。数据库中有个名称为vTbl_Fact_Store_Sales_WE_2004_11_27的关系表。在Project REAL数据库的分割表看上去违反了SQL Server 2000的基本实践原则。在Project REAL中,割表没有数据切片设置。在SQL Server 2000中,分割表必须有数据切片设置,以至于运行时引擎能够确定访问哪一个分割表。这有点类似于给查询优化器指定一个提示。在SQL Server 2005中,这不在是必须的了。现在,处理分割表会自动的构建MOLAP存储中的一个柱状图结构。这个结构标识出在分割表中包含了那些维度的成员。因而,只要存储方法是MOLAP,数据切片是一个可选的(和不使用的)属性。然而,在ROLAP存储中,或者当proactive caching包含一个ROLAP访问阶段的时候,数据切片仍可以使用。在这两个环境中,真实的实际数据,都没有被移动过,因此,系统没有机会标识一个成员。在这种情况下,如果你希望系统能够良好的运转,为分割表设置数据切片还是有必要的。

因为由MOLAP结构动态地决定数据切片,因此在SQL Server 2005中,一种新类型地分割技术是有可能存在的。最好的描述这种技术是通过一个简单的例子。

假定你正在设计的系统由一个包含1000个产品的产品维度。在这其中,前5个产品占到了80%的销售,而剩下的995个产品只占到了20%。这种用来显示基于产品的查询结果的终端用户查询样式分析是一种通用且有效的分割模式。例如,绝大部分报表包含了通过产品分类的详情。基于这种分析,你可以创建六个分割表。前五个分割表都分别对应一个排在前五位的产品,第六个分割表包含了其它所有的产品。创建这个包含所有其它产品的分割表是很容易的。在查询绑定中,在SQL语句中添加Where子句就可以实现。如下面的代码所示:
对于前五位的产品,使用如下的代码:
        SELECT * FROM <fact table>
        WHERE SK_Product_ID = <SK_TopNthProduct#>

对于查询包含其它产品的分割表,使用如下代码:
        SELECT * FROM <fact table>
        WHERE SK_Product_ID NOT IN (<SK_TopProduct#>,
                                  <SK_2ndTopProduct#>
                                  <SK_3rdTopProduct#>
                                  <SK_4thTopProduct#>
                                  <SK_5thTopProduct#>)

这种技术,在SQL Server 2000分析服务上,需要大量的管理费用。在SQL Server 2000中,必须给分割表中的每一个成员指定数据切片,即使哪里有几千个成员。为了实现这个例子,你不得不创建一个包含995个成员的分割表。当一个新的成员被添加到维度中的时候,更新这个列表也是管理上面对的一个严峻问题。在SQL Server 2005分析服务中,自动在分割表中构建数据切片的功能大大消除了管理上的成本。

另外面对的一个挑战是,当创建一个带有大量分割表的系统时,如何创建几百个分割表。在SQL Server 2000中,分割表可使用分析管理器(一个非常耗时,并会有潜在错误的过程)创建,而且每次只能创建一个。或者可以让开发人员编写一个应用程序来自动的创建。

在SQL Server 2005中,SQL Server 管理环境能够一次创建多个分割表,甚至是几百个分割表。一般情况下,当你创建一个分割表的时候,你需要使用那些定义在数据源视图中的表。毕竟,这也是数据源视图存在的原因。然而,这也不是必须的。在Store Sales度量组(请确认至少已经提供或者处理了一个分割表)上创建一个分割表,然后检查对话框,如图14所示:



注意,虽然对话框默认使用数据源视图,但你也能在数据源中查找和定位表。选择数据源然后单击Find,如图15所示:



对话框列举了在数据源中能匹配包含在度量组“模板”表(或视图)的元数据(列和数据类型)的表。见图15。如果你选择了多个条目,系统会为每个选中的表创建分割表。



这回带来两个重要的侧面影响。首先,这意味着,不是所有的对象都来自于数据源视图。在Project REAL中,这意味着我们不必包含所有的23个基于周的分割表。我们只是包含了一个模板对象,用来创建度量组。第二,这也是节约时间的部分,你能够通过一个简单步骤就创建上百个分割表。仅仅只是选择多个对象,你就从一个操作中获得了大量的分割表。只是要求你在这之前已完成至少一个分割表的处理,以至于Find操作能够定位到相匹配的表。也就是这些,我们就可以通过一次点击,就能创建上百个分割表了。

存储方法(Storage method)
在我们的Project REAL工作阶段,所有的分割表都使用MOLAP存储。尽管我们正在正规测试的基础上不断扩展我们地测试工作,但我们现在还没有积极地测试这个领域。

集合和集合设计(Aggregations and aggregation designs)
集合是将被系统计算的subtotal,用来提高检索速度。和集合本身一样,系统也保存了集合的设计。这是集合到底是什么的一种内在表示。设计描述了维度的结合以及应该被计算的subtotal的级别。集合和集合设计被保留在分割表中,这些分割表又都是包含在度量组中。

和SQL Server 2000分析服务将集合设计保存在分割表中不一样的是,在SQL Server 2005分析服务中,集合设计是位于第一位的。如果你查看由数据库提供的XMLA脚本,你会看到集合设计和度量组在相同的级别上。你可以同时有多个集合设计。在一个度量组中,每个分割表都会执行一个它所使用的集合设计。这有以下几种方法:没有集合设计(这也是不必为分割表创建集合的情况);一个针对所有分割表的集合;若干个不同的集合,每个都针对若干个分割表。绝大多数应用程序都使用第一或者第二中方法(要不就不使用集合设计,要么就是所有的分割表都是用一个集合设计)。在一些更复杂的设计中,你可以使用第三种方法(多个集合设计,各自应用于若干个分割表)。例如,你可以在一个当前年的分割表中使用大量的集合,对于最近三年的分割表使用适度的集合,对于三年的分割表,则不使用集合。在脚本上,很容易将一个分割表指向不同的集合设计,只要编辑XMLA脚本即可。

处理设置和错误配置
在度量组中保留分割表的同时,系统也会记录对这些分割表的处理设置和错误配置。对于Store Inventory和DC Inventory度量组,我们可以使用默认的错误配置。这种情况下,当系统检测到无效的外部键或者当它遇到NULL值或者当遇到其它不一致数据时,它会停止处理过程。这是因为默认情况下,系统认为所有的数据都是正确的。
对于Store Sales度量组,我们不得不使用不同的错误配置,如果你还记得在在度量组里面所讨论的,我们讨论了在Customer维度和Store Sales 实际表之间发现的无效数据。由于这是因为数据反馈之间正常的不一致性造成的,因此,我们必须修改默认的错误配置。

Proactive caching设置
考虑MOLAP结构的一种方法是当它被处理的时候,提供一个缓存或者一个关系型数据的图像。SQL Server 2005提供了一个新的功能,能够靠南固执MOLAP缓存什么时候被重新处理。提供了几个你能够改变的几个设置。例如,你可以设置硬编码的时间间隔(例如每隔15分钟)。或者,你能让系统等待数据直到数据被更新后,再处理它。这些设置都是保存在分割表中的。因而,也是保存在度量组中的。在当前的Project REAL系统中,我们使用了自动的MOLAP proactive cache设置。我们计划当我们进行性能测试的时候,再调整这种设置。

其它的Cube对象
除了维度的用法、度量组和分割表,在Cube中还包含了若干其它的对象。这个章节中将简要介绍计算(calculations)、关键性能指示器(KPIs)以及其它存储在Project REAL Cube中的对象。

计算(Calculations)
在当前的Project REAL系统上实现了多个为商业度量服务的计算。例如,计算平均销售数量和库存数量。尽管我们正在正规测试的基础上不断扩展我们地测试工作,但我们现在还没有积极地测试这个领域。

关键性能指示器(Key Performance Indicators,KPIs)

在当前的Project REAL设计上还没有包含关键性能指示器(Key Performance Indicators,KPIs)。尽管我们正在正规测试的基础上不断扩展我们地测试工作,但我们现在还没有积极地测试这个领域。

活动(Actions)
当前的Project REAL设计只包含了一个活动。这个活动被用来作为分析服务客户端和报表服务之间的一个桥梁。这个单元级别的活动,当被终端用户选择的时候,它调用一个报表服务的报表,并传递给报表适当的内容作为参数(例如一个指定的Item或者Vendor)。尽管我们正在正规测试的基础上不断扩展我们地测试工作,但我们现在还没有积极地测试这个领域。

透视(Perspectives)
当前的Project REAL设计并不包含任何透视。尽管我们正在正规测试的基础上不断扩展我们地测试工作,但我们现在还没有积极地测试这个领域。

定制程序集、用户定义函数(user-defined functions,UDFs)和MDX脚本
当前的Project REAL设计并不包含任何定制程序集、UDFs或者MDX脚本。尽管我们正在正规测试的基础上不断扩展我们地测试工作,但我们现在还没有积极地测试这个领域。

服务器端设置
当前的Project REAL设计没有给便任何服务器端的设置,它们都还保留在默认值上。唯一的一个例外是在我们的一些小型系统上,我们把CoordinatorExecutionMode服务器属性设置成4。这么做的目的是为了在一个CPU或者双CPU的系统上,最多只支持4条并行操作。SQL Server 2005分析服务中,因为它试图并行化多条管理性操作,例如,维度和分割表处理,这些操作在SQL Server 2000分析服务中都是连续的,但现在这可能会带来一些问题。分析服务提供了两种方法用来限制并行化程度。

你能限制在request-by-request基础上限制并行化程度。首先,选择类似维度或者分割表这样的对象。你能在商业智能开发环境(BI Development Studio)和SQL Server管理环境(Management Studio)中选择多个对象,然后按下Ctrl键或者Shift键,用来选择多个条目,完成一个操作。一旦你选择了对象,Process Object(s)对话框就会出现,如图17所示,在单击Change Settings。



然后你能够限制系统,例如,每次最多只能处理4个请求。如图18所示。尽管这个下拉框中的数字是成倍增长的,但你可以随意输入整数值。



你也能在用来完成处理的XMLA脚本中控制并行化程度。如图19所示。



这个方法存在的问题是你不得不在每次处理对象的时候都需要设置它。如果系统中包含太多这样的对象,这将变的很难。例如,处理一个带有231个分割表的Cube就是很困难的。

事实上,如果你通过使用处理对话框将并行化程度设置为8,然后去查看语句的内容,你将看到在XMLA脚本中的MaxParallel属性被设置的值,就是刚才执行的值。

你也能够在服务器端设置最大的并发请求。这在一些场景中会有更好的效果(例如,你不在需要记着每次都设置它)。然而,在其它很多场景中,例如当你正处理小数目的并发请求或者当正执行的SQL语句稍微有点超载的时候,这不会有任何帮助。

改变系统端限制
1.        在SQL Server 管理环境中单击服务器,然后选择Properties。
2.        改变CoordinatorExecutionMode属性的值。
3.        单击OK.



你将注意到在属性对话框中有Restart列,并暗示不需要重新启动服务,新的值将立刻生效。

设计抉择
这个章节中将检查一下我们遇到的两个具有挑战性的设计问题。第一个是在设计中如何表示Vendors。我们原来在SQL Server 2000分析服务中使用的模型化技术,应用到Project REAL的时候遇到了一个严重的冲突。我们将在下文回顾它们并提出了五个方法解决这些问题。

另外一个挑战是在数目数据上如何完成计算。我们注意到许多数目计算包括库存数量、定购数量不一定都是可加减的(不是基于SUM、MIN、MAX、COUNT)。我们通过使用SQL Sever 2005分析服务中新的半加性度量来解决这个问题。

如何表示厂商
在Project REAL开始的设计中,厂商被SQL Server 2000中五个虚拟的维度模型化。分别是:
•        Return Vendor –退货的厂商
•        Purchase Vendor – 购货的厂商
•        Original Purchase Vendor – 第一次购货的厂商
•        Source Vendor – 过渡货品(可能既不是购买,也不是退货)的厂商
•        DC Vendor – 提供销售中心的厂商
在下面的五个章节中,我们比较和对比了五种使用SQL Server 2005分析服务来模型化实体的方法。我们发现,没有一种简单的方法能够实现所有环境中的关系型模型化。我们发现最好根据运行时可用的存储、所允许的计算来选择使用的方法,从而实现更有弹性的厂商分析模型。

方法#1- 创建单独的真实维度
我们实现的第一种方法是创建了五个真实维度(每个都对应一种厂商类型),并从Item维度表中加载。这种技术很直接,并且很容易实现。然而,它存在一些缺点。首先是它在Cube中带来了一些额外的复杂性。终端用户不得不多使用增加的五个维度。并且在维度存储上也增加了五倍以上(因为每个维度完全不依赖于其它的维度)。最终要的缺点是这种技术不可能实现交叉的厂商分析。例如,考虑“Abrams, Harry N., Inc.”这个厂商。因为Abrams有五个成员,因此无法通过厂商直接的来分离,除非你假定,Abrams在五个维度中都有相同的拼写,并且确保在所有五个维度中都选中这个相同的切片。

方法#2 – 使用属性层次来代替物理维度
这个方法相比于前面的方法,使得货品和厂商之间的关系更加密切。在这种方法中,我们去掉了第一种方法中使用的物理维度,而是在Item维度上添加了五个属性或者用户定义的层次。这五个新的Item层次是:Item.Return Vendor,Item.Purchase Vendor,Item.Original Purchase Vendor,Item.Source Vendor和Item.DC Vendor。使用这种方法,有以下几个优点。首先,因为五个属性是从一个属性键下构建的,因此只需要一个存储位置。第二,因为我们将五个维度转换成五个属性层次(或者用户定义层次),因此这降低了最终Cube的复杂度(维度)。对于一些终端用户,这点很重要,这能使得他们在Cube之间导航更加简单。然而,这种方法也不允许覆盖多个厂商的分析。

方法 #3 – 为Vendor和Vendor类型创建多对多的维度
第三个方法是在三个维度(Item, Vendor和 Vendor Type.)之间创建一个多对多的维度,这是一个不常用的方法,这会带来大量的成本。Item维度并没有任何变化。Vendor维度需要在五中类型的厂商上将所有可能的厂商合并(并去除重复的项)。最后,Vendor Type已经有五个成员,分别为Return、Purchase、Original Purchase、Source和DC服务。一旦维度就绪后,就创建一个度量组,用来表示每个Item和它的五中类型。度量组看上去的效果如图21所示。



如同你看到的一样,这个度量组确实非常大。在完整的维度中,我们会有超过六百万个项货品,每项有五种类型,以及约4万个厂商。这意味着,在这个多对多的度量(在Cube设计中被称为Item Vendor)组中,我们会有超过3千万项记录。
这个方法的主要缺点是为了完成对厂商的分析,你必须构建一个在正被分析的分割表数据之间的百万对百万级别的交叉连接和一个多对多的度量组(也包含几百万条记录)。这意味着,在第二种方法中只需要几秒的查询,在这种方法中会慢上许多(例如几十妙)。但是,这种方法也带来了巨大的好处。现在,你可以用一个独立的成员表示一个成员。这能够让成员更容易被区分,并能够直接的比较。如图22所示。



这在其它技术中是不可能实现的,除非你手工的把五个切片设置成相同的值。
方法#4 – 使用一个引用或者扮演角色的维度
第四种技术将创建一个单独的Cube维度,被称为Vendor,就像多对多的这种方法一样,它有一个单独的成员,值都是来自于Item维度表中每个被联合的厂商。然后再将这个维度添加到Cube(每次都对应一个角色),作为一个引用或者扮演角色的维度。第一次,Vendor维度被称为Return Vendor;第二个被称为Purchase Vendor;以下类似。虽然这个方法还是具有交叉厂商分析的缺点,但是这种方法只需最小的存储并且实现很直接。
如果你使用这种技术,需要意识到一点,和多对多方法一样,实际的计算是在运行时完成的。在适当的分割表数据和扮演角色维度之间存在一个连接,然后数据就形成了。尽管这种方法存在和多对多一样的性能问题,但这种方法不需要额外的分析能力。

方法 #5 – 使用引用或者扮演角色维度并实物化
第五种用来模型化厂商的方法是用第四种方法创建扮演角色维度,但当你指定引用维度的时候,将类型设置成“materialized”。当这个设置生效的时候,会为每个角色产生一个维度的独立拷贝。这能够提高在维度内存成本上的性能(因为不用在运行的时候连接)。

关于厂商模型化的技术总结。

总体上,这五种厂商模型化技术如下所示:
1.        实现五个真实的维度,每个都对应一个类型。这增加了维度的数量,但这种方法速度很快,并且集合能够被预先计算。

2.        在Item维度中实现五个属性层次。这减少了维度的复杂性以及厂商和Item维度之间的关联(这相比于第一种方法,更加清晰)。方法#1和方法#2一个共同的缺点在于交叉厂商的分析,因为,无论它是什么角色,那里没有一个成员,能够代表一个唯一的维度。

3.        实现了一个在Item、Vendor和Vendor Type之间的多对多维度。这种发放速度更慢一些,但是概念上却更加清晰。它允许你无需改变元数据就能添加厂商角色的数目。这使得结构更有伸缩性,并且允许这种交叉厂商的分析。因为这种多对多度量组需要大量的查询时间,因此这是一种速度最慢的方法。

4.        使用一个单独的Vendor维度,实现五个引用(或角色扮演)维度。这很容易完成,并且比头两个方法概念更加清晰。由于这种方法是在运行的时候完成的,因此这种方法的性能会受一点影响。并且,没有可以预先计算的真实集合。

5.        实现方法#4,并且将角色扮演维度再实物化。这实现起来和方法#4一样容易,但每个维度成员都需要创建来形成。这意味着能够设计集合,并实现预先计算。由于没有单独的成员来表示一个唯一的厂商(无论它是什么角色),和#1、#2一样,方法#4和方法#5都有交叉厂商共有的缺点,然而由于已经存在基础的对象,方法#4和#5相比于方法#1和#2,更加直接。所有你要做的,只是在添加第六、第七个引用或者扮演角色维度。Vendor维度已经准备就绪。但所有的四种方法都需要改变元数据,这将影响到你现有的报表和MDX查询。只有方法#3允许你在无需修改元素据的情况下,添加新的厂商类型。

在Project REAL中,我们实现的是方法#2和#3。我们捆绑了这两种方法,以至于终端用户能够能够权衡是更好的考虑性能还是更好的考虑分析功能,从而选择更适当的方法。

半可加减的存货度量
在Store和DC存活数据中有一个出名的问题。一般,当我们处理像销售总数和销售数量这种多维度的数据时,度量都时可加减的。为了得到WA地区的销售总数,你所要做的就是把所有城市的所有仓库的销售总数加起来。我们把这种计算叫做可加减的(Additive)。SQL Server 2000分析服务支持四种可加减的操作,分别是Sum, Count, Min和Max。这样,平均值就能通过Sum/Count来实现。
例如,图23中Sale Amt 列中的数据代表了Kirkland,WA仓库在某个时段的销售总数。Sum就是为计算Sales Amt的集合函数。



注意,每周的销售总数是从每天的总数计算获得,每月的总数是从每周的总数上计算获得。因此我们称总销售是一个可加减的度量。这种方法对On-Hand Qty度量适用么?显然不行。库存的数量、订单数量看上去是一些半可加性的度量。这些需要汇总的值都是基于某个时间段的一个时间点,而不是基于总数,也不是基于最后的值(或者是一些其它基于半可加性的计算)。在这个例子中,在周六统计库存的详细信息。如果在月初,Kirkland仓库书本的数量是10000,库存需要在每周六的时候都保存相同的数量(10000)直到月底(我们假定每周中每售出一本书,都会在周五得到补充),那么我们在月底的时候,存货是40000(总数)还是10000(最后的存活)呢?
为了解决这个问题,我们使用了SQL Server 2005分析服务中一个新的半加性集合函数。由于我们已经具备时间维度,我们所需要做的仅仅是把集合函数从Sum改成LastNonEmpty,这样就能实现我们预期的功能。

由于SQL Server 2000分析服务仅支持可加减的度量,原来在Project REAL设计的复杂计算都必须手工的来完成。现在在SQL Server 2005分析服务中,已经支持半可加性的操作。我们所要做的只是改变集合函数。如图24所示。



最佳实践:如果你使用半可加性的度量,请确认Cube包含的维度不超过一个。
使用半可加性的度量,有一些约束。首先,你必须有一个被标识为Time类型的维度用来使用半可加性度量。如图25所示。当它运行的时候,时间智能向导(Time Intelligence Wizard)将会合适的设置属性和维度类型属性。如果你通过标准的维度向导(Dimension Wizard)创建你自己的时间维度,你必须再手工的设置适当的类型属性。



LastNonEmpty函数不能计算所有类型的维度。它只能完成基于时间维度的计算。而且,在Cube中智能包含一个时间维度。如果在你的cube中包含多个时间维度,系统会找到第一个符合要求的去执行。这虽然不是一个必要的、优秀的、可预言的选择,但事实上,它就是这么做的。

结论
这份白皮书提供了一些关于SQL Server 2005分析服务(Analysis Services)的技术性讨论,主要是关于分析服务的设计和Rroject Real项目中的一些实际应用。我们回顾了许多很好的实践和资料,这些都是在Project REAL项目中积累下来的,并提供了各种不同类型对象的信息,例如数据源、数据源视图、维度、层次、属性、度量组和部分。

版权说明
本文只是一个初步的文档,在软件随后发布的最终商业版中,本文描述的部分内容可能会有所变化。
包含在本文中的内容,代表了微软公司在这些问题上最新的观点,直到正式发布软件为止。因为微软必须根据市场条件的变化做出响应,因此本文不应作为微软任何部门的承诺,并且微软不能保证在正式版本发布后,本文中任何信息的准确性。
这个白皮书仅用于提供信息之目的。微软公司对这个文件的信息不做任何担保、明示、暗示或者法律相关责任。
遵守所有适用的版权法是用户的义务。在不限制版权法所规定权利的前提下,未经微软公司明确的书面许可,不得以任何目的、任何形式或任何手段(电子、机械、影印、录制或其他手段)对本文档的任何部分进行复制、储存或引入检索系统、或传播。
Microsoft 可能已拥有与本文档中涉及的主题相关的专利、专利申请、商标、版权或其他知识产权。除非得到 Microsoft 的明确书面许可协议,提供本文档并不表示授予使用这些专利、商标、版权或其他知识产权的任何许可。
除非另作说明,否则文中描述的公司、组织、产品、域名、电子邮件地址、图标、人员、地点和事件都是虚构的,无意联系或暗示与任何真实的公司、组织、产品、域名、电子邮件地址、图标、人员、地点和事件有所联系。
©2005 微软公司。版权所有。
Microsoft,Visual Basic,Visual C#和 Visual Studio是微软公司在美国和/或其他国家(地区)的注册商标或商标。
此处涉及的真实公司名称和产品名称可能是其各自所有者的商标。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值