具有退化维度的蒙德里安表现不佳

Posted

技术标签:

【中文标题】具有退化维度的蒙德里安表现不佳【英文标题】:Poor Performance of Mondrian w/ Degenerate Dimensions 【发布时间】:2014-06-13 18:03:55 【问题描述】:

我有一个收集性能指标并将其存储在数据集市中的应用程序。然后,我使用 Mondrian 对数据进行分析和临时探索。我每天收集大约 5e6 行,METRIC 表的总大小约为 300M 行。

我们根据与 SLA 的指标比较为我们的数据“着色”。颜色正好有 5 个不同的值。例如,当我们执行简单的 MDX 查询以获取特定日期范围(例如 1 天)的数据颜色分布时,我们会看到如下查询:

2014-06-11 23:17:08,042 调试 [sql] - 223: SqlTupleReader.readTuples [[Color].[Color]]:执行sql [select "METRIC"."COLOR" as "c0" 从 "METRIC" "METRIC" group by "METRIC"."COLOR" order by “公制”。“颜色”ASC NULLS LAST] 2014-06-11 23:17:58,747 调试 [sql] - 223: , 执行 50704 毫秒

为了提高性能,数据集市包含小时和天级别的聚合表,并且两个聚合表都包含 COLOR 列。

我了解 Mondrian 非常依赖底层数据库的性能,但确实没有办法对此进行调整。我可以在 COLOR 上创建索引(因为索引的完整扫描将比表的完整扫描稍微快一些),但是在 300M 行表上创建具有 5 个不同值的索引似乎很愚蠢。 day 聚合表有大约 500K 行,并且针对该表执行几乎相同的查询会明显更快,但 Mondrian 似乎总是针对这些维度查询使用基本事实表。

我的问题是,有没有办法避免这个查询?如果我无法避免,是否可以让 Mondrian 使用聚合表进行此类查询?我已经在这个维度/层次结构的单个级别中指定了 approxRowCount,并且消除了类似的查询来获取值的计数。我还没有深入了解 Mondrian 的来源,以确定是否有可能使用聚合表,或者我是否有一些配置阻止了它。

编辑澄清:

我可能没有很好地提出我的问题——让我试着澄清一下。我的 MDX 查询类似于:

select [Color].[Color].Members on columns,
       [Measures].[Metric Value], [Measures].[Count] on rows
from [Metric]
where [Time].[2014].[June].[11]

我可以看看这个并手写一个 SQL 查询来回答这个查询

select COLOR, avg(VALUE), sum(FACT_COUNT) 
from AGG_DAY_METRIC
where YEAR = 2014 
  and MONTH = 6
  and DAY_OF_MONTH = 11
group by COLOR

数据库在大约 100 毫秒内扫描大约 4K 行来回答这个查询。蒙德里安需要几分钟来回答 查询,因为它执行了几个不直接回答 MDX 查询的查询,而是获取有关 方面。在上述情况下,数据库必须扫描 300M 行,花费 50 秒,返回有 5 个可能 颜色。如果颜色在正常维度表中只有 5 行,但在退化维度中可能有 100 行 数百万行。

所以我的问题是:

a) 有没有办法告诉 Mondrian 退化维度的值并避免这些查询?

b) 有没有办法让 Mondrian 从聚合表中回答这些查询?

【问题讨论】:

【参考方案1】:

解决了这个问题,不是通过修改 Mondrian 模式或应用程序中的任何内容,而是通过修改数据库。本例中的数据库是 Oracle,我们能够创建启用查询重写的物化视图。

物化视图是根据 Mondrian 发出的确切查询创建的。由于颜色值不会经常更改(在我们的例子中几乎从不),因此物化视图每天会完全刷新一次。

在这种情况下,查询从几分钟变为几毫秒。如果您面临这样的问题并且您的数据库是 Oracle,那么这是加快低基数退化维度的元组解析的好方法。

【讨论】:

【参考方案2】:

如果不了解您的架构,很难给出任何具体的指示,但在我看来,您必须确保必须将具有某些颜色(计数)的行数标记为聚合度量 (@987654321 @ 或 Max Number)。

请注意,这些聚合不是连续计算的(我认为这对于支持数据存储来说会很重,而且 Mondrian 不会在内存中为传入的事实保留一个流动的集合)。

可以指定聚合在特定时间(每晚、每小时...)运行/重建。这会使 Mondrian 有点不适合实时分析,但您应该能够对历史数据进行几乎即时的查询。

【讨论】:

感谢您的回复。有一个度量计数(聚合类型“计数”),所有聚合表都有 FACT_COUNT 列,所有聚合表都包含颜色退化维度值。我也试图澄清我的问题。【参考方案3】:

如果您的维度在 300M 事实表中有 5 个不同的值,则它不应该是退化维度。它应该在一个单独的维度表中。仅当其基数接近完整的事实表行数时才应使用退化维度,这使得单独的表毫无意义,因为不会显着节省存储空间,并且加入维度会导致读取大量数据;

如果您将颜色放在单独的暗表上,任何“读取元组”查询都会在几毫秒内返回结果,您的问题就解决了。

但是,更重要的是,蒙德里安应该能够从 agg 表中选择暗值。除非您在多维数据集中有非重复计数聚合器,在这种情况下您会遇到棘手的情况(除非有一个聚合表与您需要的详细程度完全匹配,否则 Mondrian 很可能会扫描事实表)。

您还应该将此退化维度的 highCardinality 属性设置为 True。即使只有 5 个不同的值,highCardinality=false 告诉 Mondrian 扫描整个维度以填充成员列表是安全的。将其设置为 true 会停止此扫描。

您还应该为此列添加索引。向事实表中的每个键和退化维度列添加索引总是一个好主意。有了索引,数据库的响应速度应该比 SQL 查询快得多。

最后,您有一个 300M 行的事实表。您使用的是什么 DBMS?它是面向列的数据库吗?如果没有,您应该尝试将它们作为数据存储的可能替代方案。对于类似蒙德里安的查询,面向列的 DB 比面向行的 DB 具有显着的性能提升。有一些不错的选择,您应该试驾一下。

【讨论】:

我使用退化维度的决定只是基于与蒙德里安文档 (mondrian.pentaho.com/documentation/…) 中描述的情况完全匹配的事实。这个维度是如此简单,以至于添加一个额外的并产生额外的连接成本(似乎)没有意义。 至于 highCardinality,我将其设置为 false(默认),因为据我了解,它主要用于事实表按维度分区时。我们正在考虑分区,但不在颜色维度上(一方面分布在颜色上非常偏斜)。我会试一试,但我知道蒙德里安会为每个成员发出查询(在这种情况下并不可怕)。最后,我从 Julian Hyde 那里读到了 cmets,他不喜欢这个功能,想从 4.0 中删除它。 (julianhyde.blogspot.com/2011/06/…) 我也不喜欢这个功能,但这不等于说它没有影响。远离退化维度,你的性能问题就解决了。可能,只需将维度设置为高基数也可以解决问题。 使用 highCardinality 标志不会提高性能。此标志仅使得当 Mondrian 构建元组列表时,它并行使用链表和 DB 游标,因此它只对所需的元组进行水合,并且可以安全地通过列表而不会炸毁 VM 堆。您还需要了解与解析元组和解析单元格相关的查询之间的区别。聚合表可以用于后者,但让它们对前者有用是相当困难的。 我的测试证实了 Luc 所说的。我有一种感觉,Mondrian 可能很难利用 agg 表来解析元组(否则 Mondrian 已经在这样做了),但我希望这可能是我的配置或使用方面的阻碍。我正在使用带查询重写的物化视图来改善性能不佳的全表扫描,从而取得了一些进展。

以上是关于具有退化维度的蒙德里安表现不佳的主要内容,如果未能解决你的问题,请参考以下文章

使用蒙德里安模式的数据仓库中的多对多维度

在 Mondrain Schema 中定义时间维度?

蒙德里安非星型模式,多个事实表

mondrian mdx 过滤日期维度中年份级别的集合

当 MDX 查询包含 2 个或更多级别的相同维度时,速度较慢

Mondrian Schema - 计算的成员维度查找