SQL Server 2008 Analysis Services 中对 MDX 的性能改进

在此版本的 Analysis Services 中,重点对多维表达式 (MDX) 计算的执行性能进行了改进。为了获得这方面的性能提升,对引擎体系结构进行了多项重要更改。但要分享这些性能提升带来的好处,还必须对您的 MDX 代码进行优化。

本文档将帮助您了解在您的现有 MDX 代码中,会阻碍您分享这些性能提升的问题之所在,并提供在编写新的 MDX 代码时如何避免这些问题的建议。本文档还包含一个函数列表,其中的函数从这些性能提升中获益。

检查您的代码以获得最大程度的 MDX 性能提升

检查代码时,应尝试避免出现下面各种情况和代码编写方式,因为它们可能会阻碍您的 MDX 语句分享 SQL Server 2008 Analysis Services (SSAS) 中的性能提升成果。但若没有切实可行的方法来改变您的代码以避免述及的情况,则您的 MDX 代码的性能仍保持与在 SQL Server 2005 Analysis Services (SSAS) 中一样。

有用的定义

空间

对其计算表达式的单元集。

任意形状

不能以两个或多个集合的交叉联接来表达的空间。例如,空间 {(Drink, USA), (Food, Canada)} 表示一个任意形状,因为它是 {Drink, Food} * {USA, Canada} = {(Drink, USA), (Drink, Canada), (Food, USA), (Food, Canada)} 间的交叉联接的子集。

静态表达式

如果一个表达式对于计算自己的空间而言是不变的,则称其为静态表达式。

例如,对于空间 CrossJoin(Product.Members, Customer.Members),下面的表达式就是不变的。

  • 1,常量表达式

  • Product.Members.Count

动态表达式

如果一个表达式对于计算自己的空间中的每个单元可解析为不同的值,则称其为动态表达式。

例如,对于空间 CrossJoin(Product.Members, Customer.Members),下面的表达式就是动态表达式。

  • Sales,因为对于该空间中的每个单元,度量值 Sales 的值是不同。

可变属性

表达式的计算方法是由可变属性确定的,因此表达式依赖于可变属性。例如,表达式 Customer.Geography.CurrentMember 依赖于地域 (Geography) 层次结构中的属性。

通常,可变属性可缩减计算表达式的空间。请看下面的表达式:

with member measures.x as Customers.Geography.currentmember.uniquename

Select Customers.Geography.City.members on 0,

Product.members on 1

From sales

Where measures.x

在此表达式中,Customers.Geography 是一个静态表达式。currentmember 函数是一个可变属性,因为它引入了对 City 属性的依赖。Uniquename 不增加可变属性,因为它以 1:1 的关系绑定到了 currentmember。因此,对每位客户都只计算一次 uniquename,对每个 Product 也不会重复计算该项。这样,可变属性就有效地缩减了整个表达式空间。

在单元的非值属性中使用表达式

用于分配一个单元的非值属性值的所有 MDX 表达式不会从性能提升中获益。其性能仍将保持与在 SQL Server 2005 Analysis Services (SSAS) 中相同的水平。

使用未列出的函数

在 MDX 代码中使用任何本文档中未列出的函数将不会从此版本产品的预期性能提升中获益。请参阅本文档中的Functions with enhanced performance。

使用单元安全性

如果在代码中对定义了单元安全性的空间计算 MDX 表达式,您的代码将无法获得性能提升。

下表列出了单元安全性和性能之间的关系。

单元安全性

预期性能

最佳

读取

中等

有条件读取

最差

请参阅使用 MDX 表达式设置单元数据权限授予对单元数据的自定义权限

使用动态维数

在 MDX 代码中使用动态维数表达式将会使您的代码无法获得性能提升。例如,类似 Sum( IIF( Sales > 10000, h1.Members, h2.Members)) 的表达式无法获得性能提升,因为您的代码会在计算 Sales 表达式时更改要计算总和的成员。另一个示例是这样一个应用场景,其中,您需要使用一个来自 Calendar Year 层次结构的成员或一个来自 Fiscal Year 层次结构的成员,这两个层次结构都依赖于一个属于 Account 属性的当前成员的属性,以与某个并行期间的等价值进行比较。此应用场景所需的 MDX 表达式类似于下面的示例代码。

ParallelPeriod(Iif( Account.CurrentMember.Properties("UsesFiscalCalendar")="Y", FiscalTime, CalendarTime).CurrentMember)

其维度也会随 Account 维度当前成员的变化而动态变化。

使用动态参数

在 MDX 代码中使用动态参数将会使您的代码无法获得性能提升。例如,类似 KpiGoal("Sales_" & [Fiscal Year].currentmember.UniqueName) 的表达式对于计算其值所用的不同单元是变化的,相反,表达式 KpiGoal("Sales_" & Cstr(Year(Now))) 是不变的。

重要说明重要提示

可能有这样的情况,表达式 KpiGoal("Sales_" & [Fiscal Year].currentmember.UniqueName) 对于计算其值的整个空间会得出相同的值,但这还是不足以使引擎提供期望的性能提升。

动态成员引用

在 MDX 代码中使用任何动态成员引用都会使您的代码无法获得性能提升。例如,在下面的表达式中:

(IIF( e, mbr1, mbr2), Sales)

直到执行时计算 IIF() 表达式之前,是无法知道结果元组的。但在下面的等价表达式中:

IIF( e, (mbr1, Sales), (mbr1, Sales))

在计算表达式 e 之前,两个结果元组中的任一个都是已知的。

计划提示

计划提示是对 MDX 语言的扩展,用于指示引擎如何计算表达式。在此版本的 Analysis Services 中,仅在 IIF(,,) 函数中引入了计划提示。

可以在 MDX 表达式中指示计划提示,也可以在服务器配置属性中全局配置计划提示。

IIF() 函数中的计划提示

在 IIF(,,) 中,使用下面的语法指示表达式提示:

IIF(<cond>, <expr>, <expr>) [HINT <hints>]

<expr> ::= <expr> [HINT <hints>]

<hints> ::= <hint> [<hints>]

<hint> ::= EAGER | STRICT | LAZY

  • EAGER 会导致针对整个 IIF 子空间计算表达式。

  • STRICT 会导致根据条件表达式的结果仅在结果子空间中计算表达式。

  • LAZY 会导致以逐个单元的模式计算表达式。

  • 在提示中,EAGER 和 STRICT 是互斥的;可以在不同表达式的相同 IIF(,,) 中使用它们。

语法示例:

IIF([Measures].[Internet Sales Amount]=0

, {([Date].[Calendar Year].CURRENTMEMBER, [Customer].[Country].[All Customers])} HINT EAGER

, {{[Date].[Calendar Year].CURRENTMEMBER} * [Customer].[Country].[Country].MEMBERS} STRICT LAZY

)

配置属性中的计划提示

为了支持计划提示,引入了以下配置属性,这些属性位于 OLAP\Query 路径下:

属性名称

可接受的值

说明

IIFThenMode

0 | 1 | 2

0,无提示(默认值)

1,EAGER

2,STRICT

IIFElseMode

0 | 1 | 2

0,无提示(默认值)

1,EAGER

2,STRICT

LazyEnabled

0 | 1

0,禁用(默认值)

1,启用

用户定义的存储过程(COM 或 .NET)

在 MDX 代码中使用用户定义的存储过程将会使您的代码无法获得性能提升。

注意注意

SQL Server 2008 Analysis Services (SSAS) 提供了为性能提升而经过优化的存储过程。

在参数中使用命名集或集别名

在 MDX 代码中,只要将命名集或集别名用作函数 Sum、Min、Max、Avg 或 Aggregate 中的第一个参数,则您的代码将无法从性能提升中获益。

例如,下面的 MDX 表达式计算拥有多个子级的成员数量。

Sum(h.members as S, Iif(S.Current.Children.Count > 1, 1, 0))

因为 h.members 设置了别名 S,其后使用别名集获取 Current 函数值,这将无法获得期望的性能提升。

下面的代码演示了此种情况的另一个常见示例。

WITH

SET [Core Products] AS '{[Product].[Category].[Bikes]}'

MEMBER [Measures].[Core Products Sales] AS SUM([Core Products], [Measures].[Internet Average Unit Price] * [Measures].[Internet Order Quantity])

Select [Measures].[Core Products Sales] on 0

From [Adventure Works]

成员定义中的 SUM 函数没有获得期望的性能提升,因为它是基于命名集的。

在自定义汇总表达式中使用后期绑定

如果自定义汇总表达式引用计算成员或其他任何在执行时计算的 MDX 表达式,则该自定义汇总表达式将使性能无法提升。

在脚本中使用前向引用

如果在 MDX 代码的不同语句中创建了前向定义引用,则您的代码将无法从性能提升中获益。例如,在下面的 MDX 脚本代码段中,在定义 X 时创建了一个对 Y 的前向引用。

Create Member X as Y * 2;

Create Member Y as ( Sales, [Date].[Calendar].[Month].PreviousMember);

若要更正此错误,请将 Y 定义置于 X 定义之前,如下面的代码段所示。

Create Member Y as ( Sales, [Date].[Calendar].[Month].PreviousMember);

Create Member X as Y * 2;

性能获得提升的函数

标量函数

下表列出了可期望从中获得性能提升的标量函数。该表的第一列是标量运算符。

-

OR

KEY

*

XOR

LEVELS.COUNT

/

CALCULATIONPASSVALUE

MEMBERTOSTR

+

CASE

MEMBERVALUE

<

COALESCEEMPTY

NAME

<=

HIERARCHIES.COUNT

ORDINAL

<>

ID

PROPERTIES

=

IIF

UNIQUENAME

>

IS

USERNAME

>=

ISANCESTOR

VALIDMEASURE

unary minus

ISEMPTY

VALUE

NOT

ISLEAF

 

AND

ISSIBLING

 

注意注意

任何用户定义的存储过程,无论是用 COM 还是用托管代码编写的,都不会有任何相对 SQL Server 2005 Analysis Services (SSAS) 的性能提升。有关详细信息,请参阅本文档前面的“用户定义的存储过程(COM 或 .NET)”。常量表达式,无论是文本的还是数值的,都可从性能提升中获益。

成员函数

下表列出了可期望从中获得性能提升的成员函数。

.CurrentMember

.FirstSibling

.LastSibling

.DataMember

.Item

.Lead

.DefaultMember

.Lag

.Parent

.FirstChild

.LastChild

.UnknownMember

Ancestor

KPIStatus

NextMember

Ancestors

KPITrend

OpeningPeriod

Ascendants

KPIValue

ParallelPeriod

ClosingPeriod

KPIWeight

PrevMember

Cousin

LastPeriods

StrToMember(<String Expression>, CONSTRAINED)

KPIGoal

LinkMember

 

注意注意

如果 <String Expression> 为静态表达式,则 StrToMember(<String Expression>, CONSTRAINED) 可获得最佳性能。

集函数

下表列出了可期望从中获得性能提升的集函数。

Aggregate

Max

Sum

Avg

Min

 

但在使用所列出的任何函数时,第一个参数必须为使用下列函数任意组合的表达式。

-(except 运算符)

.Children

MTD

(<set expression>,(<set expression>, …,(<set expression>)(cross join 运算符)

.Members

PeriodsToDate

*(cross join 运算符)

.Siblings

QTD

:(range 运算符)

AddCalculatedMembers

StrToSet(<String Expression>, CONSTRAINED)

+(union 运算符)

Crossjoin(<set expression>,(<set expression>, …,(<set expression>)

Tail

 

Descendants

Union

 

Distinct

Unorder

 

Except

WTD

 

Hierarchize

YTD

 

Intersect

 

注意注意

静态集(包括空集)也将从预期的性能提升中获益。

VBA 函数

下表列出了可期望从中获得性能提升的 VBA 函数。

Abs

CLng

Len

CDate

CStr

Now

CDbl

Int

Right

CInt

Left

Round

对于下面的 VBA 函数,如果是通过可变属性计算该函数的,则可期望从中获得性能提升。

Asc

Format

Sgn

AscW

FV

Sin

Atn

Hex

SLN

Cbool

Hour

Space

Cbyte

Ipmt

Sqr

Ccur

Lcase

Str

Cdec

Log

StrComp

Chr

Ltrim

StrConv

ChrW

Minute

String

Cos

Month

SYD

CSng

Nper

Tan

Cvar

Oct

Timer

Date

Partition

TimeSerial

DateAdd

Pmt

TimeValue

DateDiff

PPmt

Trim

DatePart

PV

TypeName

DateSerial

QBColor

Ucase

DateValue

Rate

Val

Day

RBG

Weekday

DDB

Rnd

Year

Exp

Rtrim

 

Fix

Second