具有退化维度的蒙德里安表现不佳
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 已经在这样做了),但我希望这可能是我的配置或使用方面的阻碍。我正在使用带查询重写的物化视图来改善性能不佳的全表扫描,从而取得了一些进展。以上是关于具有退化维度的蒙德里安表现不佳的主要内容,如果未能解决你的问题,请参考以下文章