可供选择的聚合

当人们想起 OLAP 多维数据集的结构时,他们通常想到的是一组分层维度和一组使用求和来确定度量值的度量。多维数据集通常包括通过使用求和来聚合的度量。目前存在各种其他的聚合类型,但 Analysis Services 并非对所有这些类型都提供本机支持。非传统聚合的一个典型示例是库存分析。当您分析库存时,您不需要通过对三个月来的库存数字求和来确定每个季度的库存;您只需要使用该季度最后一个月的库存量。您可以在 Analysis Services 中轻松地实现这种聚合,但它不是您可以选择的本机聚合类型之一。我们先讨论本机类型,然后了解如何实现两个非本机聚合类型。

本机聚合

首先,我们先提供一些术语。多维数据集单元是多维数据集中的一个位置,各个维度在该位置相交。就像您可以在 X、Y 和 Z 轴上使用数值来标识三维空间中的点一样,您可以使用每个维度中的成员来标识多维数据集中的单元。因为每个维度都有一个默认的成员,所以您不必显式列出每个维度的成员,就可以唯一地标识一个多维数据集单元。例如,元组 (USA,Drinks) 足以标识 FoodMart 2000 Sales 多维数据集中的一个唯一单元(虽然 Sales 多维数据集有 12 个维度),因为其他 10 个维度位于其默认成员的位置上(也就是说,它们已经被占用,因此您无需对它们显式命名)。

每个多维数据集单元对于多维数据集的每个度量都有一个值。有些多维数据集单元的度量值是加载的(也就是说,直接来自源数据),而有些多维数据集单元的度量值则是由聚合来确定的。聚合是 Analysis Services 通过对其他多维数据集单元执行某些数学函数来确定的值。简言之,任何叶级单元的值都是加载值,这意味着这些值是基于源数据计算的,而不是基于其他单元中的值计算的。非叶级单元值是聚合确定的。叶级单元是完全由最低层的维度成员(没有子级的维度成员)标识的单元。

asp?url=/library/en-us/dnsqlmag03/html/AlternativeAggregationsTable_01.asp" target="_blank">表 1 显示了 Analysis Services 的本机聚合类型(数学函数)和它们的说明。非重复计数是一个特殊类型,这里应该解释一下。Analysis Services 只允许一个多维数据集中有一个非重复计数度量,而且非重复计数度量的值从不聚合(即从不通过其他单元值来确定)。在处理多维数据集时,Analysis Services 直接从事实数据表派生非重复计数度量值。非重复计数值是由特定多维数据集单元所标识的非重复类型的事实数据表记录数来确定的。例如,如果多维数据集单元是 (1997,Beverages),则非重复计数就是 1997 年期间在 Beverages 产品类别中出现的不同类型的事实数据表记录的数量。当您创建非重复计数度量时,应在事实数据表中指定一列,用于确定事实数据表记录的类型。非重复计数度量不同于典型的计数度量,因为非重复计数不是事实数据表记录的计数,而是事实数据表中特定列的非重复值的计数。数据库管理员通常使用非重复计数来确定当一个以上的事实数据表记录来自同一个事务时存在的唯一事务的数量。

本机聚合类型的一个特征是,Analysis Services 在所有多维数据集维度中用同样的方式来处理它们。非本机库存聚合则不具备这一特征。对库存量进行聚合时,您要对除 Time 维度之外的所有维度使用求和。您可以通过使用最后一个子级(也就是最近的值)对 Time 维度进行聚合。sqlserver/art/AlternativeAggregationsFigure_01.gif" target="_blank">图 1显示了 Product 维度如何将各个库存总数聚合为一个总和,而 Time 维度则使用最后一个子级。

sqlserver/AlternativeAggregationst.mspx#top"> 返回页首

非本机聚合

因为 Analysis Services 不提供对最后一个子级聚合的本机支持,所以您不得不自己创建聚合支持。对于如何实现此目的,您可以有几种选择。您可以在 Time 维度中使用计算度量、计算单元或自定义汇总公式。我倾向于使用将性能影响限制在多维数据集的最小百分比的方法。例如,FoodMart Sales 多维数据集包含除库存量度量之外的其他度量,因此我建议挑选一种不向其他度量增加额外处理的方法。Analysis Services 会计算每个度量的自定义汇总公式,因此自定义汇总不是解决这一问题的适当选择。您可以使用计算单元或计算度量方法来分离聚合处理,这样它只会影响库存量度量。当您在计算单元和计算度量之间进行选择时,您需要考虑两个情况。注意,计算单元只能随企业版的 SQL Server 提供。但计算度量在支持钻取的多维数据集中会出现问题,因为当您指定计算度量作为标识多维数据集的单元的元组(即成员列表)的一部分时,不能使用钻取操作。

为了进行库存分析,我建议使用计算度量,这只是因为大多数 OLAP 前端工具都提供了创建计算度量的功能。例如,当您在 FoodMart Sales 多维数据集中使用以下计算度量公式时,它返回 [Unit Sales],就好象它是库存量一样:

IIF( Time.CURRENTMEMBER.LEVEL
.NAME <> "Month",Time.CURRENTMEMBER.LASTCHILD,(Time.CURRENTMEMBER,[Unit Sales]) )

这个递归公式确定当前 Time 成员的级别名称是否为 Time 维度中的最低级别,如果不是,则返回当前成员的最后一个子级。该公式的 LASTCHILD 部分使公式不断重新进行递归求值,直到级别的名称为 Month;然后,该公式返回当前 Month 的 Unit Sales 值。

有些多维数据集不包含每个叶级 Time 成员的加载值。在那些多维数据集中,您不能使用上面那样简单的公式来确定度量的最近的值。我在构建一个用于跟踪软件缺陷的多维数据集时就遇到过这样的情况。该多维数据集是用包含缺陷状态转变的事实数据表构建的。软件质量保证流程通过 state 来跟踪缺陷,这些状态的名称包括 found but not assigned to a developer、assigned to a developer、fixed but awaiting the next product build、fixed but not verified 或 closed。缺陷状态转换就是从一种状态向另一种状态转换时发生缺陷的情况。例如,每个条目都包含缺陷 ID、说明、发生变化的日期、原来的状态和新的状态。我使用的事实数据表包含 date that the defect changed 状态、origination 状态和 destination 状态。要在多维数据集中创建一个返回任何时期的缺陷状态的度量,必须包括一个回溯到最近的 date that the defect changed 状态的公式:

IIF( Time.CURRENTMEMBER.LEVEL
.NAME <> "Month",TAIL( FILTER( [Time].[1997]
.[Q1].[1] : Time
.CURRENTMEMBER,NOT ISEMPTY( [Unit Sales] ) ) *
{ [Unit Sales] },1 ).ITEM(0) )

这个 MDX 表达式比前一个复杂得多。该表达式背后的原理与前一个表达式一样,但并不是只使用 (Time.CURRENTMEMBER,[Unit Sales]) 作为 IIF() 函数的最后一个参数,它可以标识最近的非空月份。首先,采用包括所有月份的一组月份,从第一个月 ( [Time].[1997].[Q1].[1] ) 到当前月份 - 冒号运算符 (:) 标识成员范围 - 并筛选出空月份。然后,该表达式使用星号运算符 (*) 将 Unit Sales 与这组非空月份进行交叉联接,使用 TAIL() 函数将这个集合减少到最后一项。ITEM(0) 运算符将 TAIL() 函数(一个集合)的结果转换为它的第一项。

在上面的两个 MDX 示例中,我使用了 FoodMart Sales 多维数据集中的 Unit Sales,这样就可以对 MDX 进行试验。在实际应用中,您应该用加载的度量替换 Unit Sales。因为您必须使用本机 Analysis Services 聚合类型之一来创建加载的度量,所以当您将该度量与非叶级 Time 维度成员一起使用时,该度量不会返回有效信息。由于可能返回无效数据,您需要将加载的度量的可见性设置为 false,这样一来,您的应用程序的最终用户所能看到和使用的就只有计算度量了。当您选择了度量后,您可以在 Analysis Manager 的多维数据集编辑器的“属性”窗格中更改加载的度量的可见性。

目前还存在许多其他聚合类型,有些聚合类型十分简单。例如,一个普通的 OLAP 应用程序要对企业收益表进行建模。在收益表的最高级别,您需要从收入中减去支出,以创建净收入。在此维度中的所有其他级别,您需要通过使用求和来聚合帐户类别。在这种情况下,自定义汇总函数可能是最合适的选择。

计算度量、计算单元和自定义汇总都是可以帮助您定制聚合公式的工具。如果您知道如何使用 Analysis Services 的高级功能,Analysis Services 就显得非常灵活。我希望通过通读这些示例和解释,能有助于您更有创造性地考虑如何创建您的 OLAP 多维数据集,这样多维数据集就可以用适合您尝试解决的问题的方式来聚合度量值了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结