概览
SQL Server 2005 的Analysis Services 引入了一些新的MDX语法,从而提供了比同等的AS 2000的查询语句更好的性能。
下面列出了一些技巧,可以帮助在AS2005的MDX查询中获得更好的性能
详细内容
- 先过滤,再做Crossjoin
首先过滤集合,然后在Crossjoin内使用。 Filter函数会物化整个集合并且轮训整个集合,然后用符合条件的元组建立一个新的集合。
避免:
filter(NECJ({set1},{set2}),..)
推荐:
NECJ(filter({set1},...),{set2})"
- 使用Rank()代替Intersect()检查集合中成员是否存在
Intersect的缺陷在于,它检查集合中成员的时候,将成员看做一个集合,这在求值过程中不能生成优化的执行计划
避免:
iif(intersect({ACTUALS_DAYS_SET},{[TIME DIM].[Time Main].currentmember}).count)>0
推荐:
iif(rank([TIME DIM].[Time Main].currentmember, {ACTUALS_DAYS_SET})>0
- 用大括号包含Crossjoin内部的单一成员
在Crossjoin的时候总是使用集合,因此即使是单一的成员也要用大括号包含
避免:
Sum( [FINANCIAL VERSION DIM].[Financial Version].[Financial Version Type].&[WSLT]
*{[GROUP STATUS DIM].[Group Status].[Group Status Name].[cancel]
,[GROUP STATUS DIM].[Group Status].[Group Status Name].[turn down]},measure)
推荐:
Sum(
{[FINANCIAL VERSION DIM].[Financial Version].[Financial Version Type].&[WSLT]}
*{[GROUP STATUS DIM].[Group Status].[Group Status Name].[cancel]
,[GROUP STATUS DIM].[Group Status].[Group Status Name].[turn down]},Measure)
- 计算成员中避免不必要的 .CurrentMember
添加不需要的 .CurrentMember不是一个好习惯。如果在MDX中不适用 "CurrentMember"来获取维度的当前成员,可以让计算引擎生成一个更好的查询计划。CurrentMember是隐式的(默认),不需要显式包含在查询中
下面的MDX中[TIME DIM].[Time Main].[Year].currentmember 是没用的
WITH
MEMBER [Measures].[M] as
'([TIME DIM].[Time Main].[Year].currentmember
,[FINANCIAL VERSION DIM].[Financial Version].[Financial Category].&[ACTL])'
select
{[TIME DIM].[Time Main].[Year].&[2005].members}
*{
descendants([GROUP EVENT DIM].[Group Event].[Hotel].&[12]
,[GROUP EVENT DIM].[Group Event].[Group Event])}
- 使用Exists函数
尽量的使用Exists函数替代筛选成员属性
- 避免Lookup
避免使用lookup函数,尝试通过在同一Cube中进行修改来提供度量值。
- 对于单一成员使用Minus而不是Filter
当从集合中筛选单一成员时使用Minus
避免:
filter({set},.Currentmember <> "UNKN")
推荐:
( {set} minus {&[UNKN] member})
- 杜绝使用值为常量的计算成员
尽管在简单的例子中可能没有差别,但是和其他计算混合时,就会产生非常复杂的执行计划。
避免:
with
member [a].[NiceName] as '[a].[123]'
member [Time].[YearBefore] as 'parallelperiod( [Time].[year], 1, [Time].[2006].[jan] )'
select { [a].[NiceName] } on 0,
{ [Time].[2006].[jan], [Time].[YearBefore] } on 1
from [MyCube]
推荐:
select { [a].[123] } on 0,
{ [Time].[2006].[jan], [Time].[2005].[jan] } on 1
from [MyCube]
- 如何检查cell是否为空?
通常,检查空cell是为了避免除0错误或是检查是否丢值(NON EMPTY分析)
- 检查非空,避免除0
IIF(b=0,NULL,a/b)
在算术操作中空cell都是0
- 检查空cell(NON EMPTY分析)
Filter([dimension].[hierarchy].member.members, isEmpty(dim.member))
这里使用了IsEmpty函数。细心的读者可能发现,如果cell值为空就会被当做0处理,但是如果b有值,而且值为0,这就是非空了!因此,在用户希望区分空值或者遗漏值的时候,就要使用IsEmpty,但是对于除0就不适用了。
注意:不要使用IS操作符(ie: IIF(b IS NULL, NULL, a/b)) 检测cell值是否为空。IS是检查成员b是否存在。
- 杂项
- 避免赋给cell类似于0, Null, “N/A”, “-“ 这样的值,cell还将是空值,另外使用Format_String做自定义UI格式。
- 避免冗余的Sum/Aggregate计算,默认的cell 会做值的聚合
- 试着避免使用IIF。如果不得不用IIF,
- see if it’s possible to write it in such a way that one of the branches (then/else) is written “null”.
- 尽量使用字面意义上的hierarchy 和member(),(e.g. 用Measures.Sales 替代 Dimensions(0).Sales, 用Product.[All] 替代 Product.Members.Item(0)).
- 如果希望获取当前cell的值,考虑使用显式的度量的名称,而不是Measures.CurrentMember
- 在编写类似于"exp1 * exp2"的计算时,避免在左值使用在Cube中有更大空间的值。比如,用“Sales * ExchangeRate”替代 “ExchangeRate * Sales”, and “Sales * 1.15” 替代 “1.15 * Sales”.
- 考虑在DSV或者SQL数据源中替换掉类似于“Measure1 + Measure2” 这样的计算
- 避免使用类似于Sum(Customer.City.Members,Customer.Population.MemberValue)这样的表达式,考虑在City表上单独定一个度量值组,带有Population列的Sum度量值