“每个A的前5个B”MDX查询的性能提示? (特别是SSAS)

时间:2011-11-30 04:07:12

标签: performance ssas mdx olap

“为每个A提供前5个B”的典型MDX示例如下所示:

-- return top 5 clients for each firm
select
  [Measures].[Amount] on columns,
  NON EMPTY generate(
    [Firms].[Firm Name].Children,
    crossjoin(
      [Firms].[Firm Name].CurrentMember,
      TopCount([Clients].[Client Name].Children, 5, [Measures].[Amount])
    )
  )
  on rows
from [FirmsAndClients]

我正在构建一个执行很多这些“前5个”类型查询的UI,所以我正在寻找任何提高它们的提示,特别是当交叉连接(A,B)主要是空值测量值时

在这种特殊情况下,公司x客户端很大(n = 5000 xn = 20,000,或多或少)并且稀疏,并且通过用过滤器替换NON EMPTY,我能够将速度提高约100倍(交叉连接内的非ISEmpty:

-- return top 5 clients for each firm
select
  [Measures].[Amount] on columns,
  generate(
    [Firms].[Firm Name].Children,
    crossjoin(
      [Firms].[Firm Name].CurrentMember,
      TopCount(
        filter([Clients].[Client Name].Children, NOT IsEmpty([Measures].[Amount]))
               5,
               [Measures].[Amount])
    )
  )
  on rows
from [FirmsAndClients]

我希望通过运行类似的查询来预热SSAS缓存,从而获得进一步的性能优势,但是我发现上面的查询(即带有“过滤器”的查询)在温暖和寒冷的情况下同样很慢缓存。在使用Sql Profiler时,我发现了部分原因:虽然SSAS缓存了底层多维数据集数据的一部分,但它似乎并不是从整个查询中缓存结果,也不是缓存由generate或crossjoin创建的中间集。因此,每次重复查询时,它都必须重做生成和交叉连接以及topcount。即使每个topcount看起来需要1毫秒或更短的时间,这些毫秒在迭代成千上万的公司时会加起来。

关于我可以做什么,MDX级别或多维数据集级别或Sql Server调优级别的任何提示?在SQL世界中,我可以在我想要排序的列上创建索引。据我所知,OLAP没有类似的东西。

可以想象,当你想要加速涉及复杂排序和过滤的MDX查询时,这是一个更普遍的问题:(显然,它不能很好地与SSAS缓存系统保持一致)。

2 个答案:

答案 0 :(得分:0)

我更多地使用了SSAS 2008,根据经验,我为这些查询开发了几个速度原则:

  • 空元组过滤可以提供帮助,但并不总是如此:正如我在原帖中提到的那样,在加入两个稀疏集之前,它可以加速一个数量级的过滤掉空元组 后一起而不是。 (通过“稀疏”我的意思是当你跨越两个时,大多数测量值都是null。)如果事先知道MDX设置你正在穿越而不是稀疏,那么TopCount( NonEmpty)优化可能会适度减慢速度。
    • 注意:如果您使用空元组过滤作为性能优化,过滤的最佳位置似乎是在调用TopCount之前(即嵌套在其中)。
    • 注意:在我的原帖中,我使用了TopCount模式(Filter(... NOT IsEmpty(...)))。但是一个可能稍微快一点并且似乎与命名集更兼容的模式是使用TopCount(NonEmpty(...),....)。
  • A)使用命名集和B)使用[MySet] .Current而不是[My Dimension]。[My Hierarchy] .CurrentMember in Generate call中的组合似乎也会带来适度的性能提升。
    • 注意:早些时候我说过命名套装给我带来了麻烦。但是,一旦我切换到NonEmpty()进行空元组过滤,我就没有问题了。

考虑到这一点,这就是我的查询现在的样子。

WITH
SET [Set0] as [Firms].[Firm Name].Children
SET [Set1] as generate([Set0], crossjoin([Set0].Current, TopCount(NonEmpty([Clients].[Client Name].Children, [Measures].[Amount]), 5, [Measures].[Amount])))
SET [Set2] as generate([Set1], crossjoin([Set1].Current, TopCount([Time].[Year].Children, 5, [Measures].[Amount])))
SELECT
[Measures].[Amount] on columns,
NON EMPTY [Set2] on rows
FROM Lobbying2

在这种情况下,我对Set1使用NonEmpty,因为Firms x Clients很稀疏,但是我没有对Set2使用NonEmpty,因为FirmClientPairs x Time不是稀疏的。

我还注意到,使用命名集可以更容易地构建嵌套的“前五名中排名前五的...”类型查询,这很有趣。

答案 1 :(得分:-2)

如何改善以下MDX查询性能?

让我解释一下为改善表现而采取的步骤。

SELECT non empty([Measures].[HC_ALLOCATED_CNT_ASSIGNMENT]*[BI FCT PROJ ASSIGN].[ASSIGN CATEGORY 1].[ASSIGN CATEGORY 1].MEMBERS *[BI FCT PROJ ASSIGN].[ASSIGN CATEGORY 2].[ASSIGN CATEGORY 2].MEMBERS) ON AXIS(0),([BI DIM PROJECT].[PROJECT CODE].[PROJECT CODE].MEMBERS*[BI DIM PROJECT].[UNIT CODE].[UNIT CODE].MEMBERS*
        [BI DIM PROJECT].[SUBUNIT CODE].[SUBUNIT CODE].MEMBERS*
        [BI DIM PROJECT].[CURRENT PROJECT DESCRIPTION].[CURRENT PROJECT DESCRIPTION].MEMBERS*[BI DIM PROJECT].[CURRENT BILLING TYPE].[CURRENT BILLING TYPE].MEMBERS *[BI DIM PROJECT].[CURRENT MANAGED BY].[CURRENT MANAGED BY].MEMBERS *[BI DIM PROJECT].[CURRENT PROJECT OFFSHORE OU].[CURRENT PROJECT OFFSHORE OU].MEMBERS*[BI DIM PROJECT].[CURRENT ACCOUNT NAME].[CURRENT ACCOUNT NAME].MEMBERS*[BI DIM PROJECT].[CUSTOMER CODE].[CUSTOMER CODE].MEMBERS*     [BI DIM PROJECT].[CURRENT AD MAILID].[CURRENT AD MAILID].MEMBERS *[BI DIM PROJECT].[CURRENT AM MAILID].[CURRENT AM MAILID].MEMBERS *[BI DIM PROJECT].[CURRENT PD MAILID].[CURRENT PD MAILID].MEMBERS *[BI DIM PROJECT].[CURRENT PM MAILID].[CURRENT PM MAILID].MEMBERS *[BI DIM PROJECT].[CURRENT PROJECT STATUS].[CURRENT PROJECT STATUS].MEMBERS*[BI DIM ASSOCIATE].[FULLNAME].[FULLNAME])ON AXIS(1) FROM [CUBE_IAMIS]