用于处理事实表中的不同计数的聚合表

Posted

技术标签:

【中文标题】用于处理事实表中的不同计数的聚合表【英文标题】:Aggregation Tables to handle distinct-count in fact tables 【发布时间】:2014-08-06 21:50:20 【问题描述】:

我正在构建人力资源 OLAP 架构,但在计算员工人数时遇到了很多麻烦。听起来很简单,但实际上遵循 OLAP 事实表设计和处理不同的员工非常棘手。基本上我遵循Ralph Kimball 制定的以下模型。我有一个 Employee 表,它表示对员工执行的事务,然后我有一个 Empty 表,它是事实表。

在 Ralph 的示例中,他仅按月计算事实表(即 month_key),但在我的表中,我可以按月、季度、年等计算。在月级别,一切正常,因为没有单个员工的重复条目。但是,将层次结构向上移动到季度或年度,单个员工会被重复计算或更多。例如,如果一个员工在 1 年内工作了 12 个月,如果你总结他的记录,他将被计算 12 次!

问题是由于这些重复条目,您无法汇总表中的数字。我尝试了其他几种方法,但它们都没有真正可靠地工作。但我考虑了一下,认为我可以为就业日期的每个级别创建汇总表。一张用于年度的表格,一张用于季度的表格,等等。这样我的加载程序可以决定如何计算每个级别的员工,并确保只有一名员工被汇总。我的数据逻辑结构保持不变。从查询的角度来看,我仍然可以考虑以年、季度、月等为单位的数据。

这是对聚合表的适当使用吗?我从未听说有人将它们用于此目的。我不是用它来提高性能,而是用它来规范化数据,并确保以一种可以聚合的方式加载所有内容,而不用担心重复。我的查询不会改变吗?我仍然可以执行以下操作:

从 [Employment] where [EmploymentDate].[2014] 中选择 ROWS 上的 [Measures].[headcount] 列上的 [Measures].[headcount]。

在 [Employment] where [EmploymentDate].[2014].[5] 中选择 ROWS 上的 [Measures].[headcount] 列上的 [Measures].[headcount]

Mondrian 将使用适当的表从中提取数据,而无需我在查询中指定它。

【问题讨论】:

【参考方案1】:

不同的计数是一个充满问题的世界。不惜一切代价避免它。

问题1:执行“select count(distinct some_column) from some_table”非常慢;

问题 2:不重复计数不聚合,这意味着您不能在某个详细级别获取总计并将它们组合以获取另一个级别的总计。因此,您不能“选择最近的聚合表”,您需要选择“确切的聚合表”。因此,会发生两件事:

每个层次结构的每个级别组合都需要 1 个聚合表 缺少一个或多个 agg 表意味着 Mondrian 需要直接从事实表中获取数据。

就您而言,这意味着如果您有公司-部门-团队和日期-年-季度-月层次结构,您将需要:

公司/所有和日期/年份级别的汇总表 公司/所有和日期/季度级别的汇总表 公司/所有和日期/月级别的汇总表 还有 3 个,现在在部门级别 团队级别还有 3 个

随着维度的增加,事情只会变得更糟,您最终可能会得到数百个 agg 表。

更糟糕的是,没有办法强制 Mondrian 选择 agg 表 A 或 B。它会以一种半模糊的方式选择(或不选择)一个,而用户几乎无法控制。

另外,必须进行不同的计数来构建聚合表意味着您的聚合脚本会很慢。

一些替代方案:

    不要对该度量使用聚合。面对这样一个事实,即这些不同的计数无论如何都需要来自事实表; 构建快照事实表,将月至今、季度至今和年初至今的唯一计数作为 3 个单独的列。将您的“快照”日期作为具有 hasAll=false 的层次结构并跳过所有级别,这样您要么选择一个日期,要么什么也看不到(因为您无法跨快照汇总); 尽量避免以某种方式进行非重复计数。一种可能的方法是跟踪“自 ETL 上次看到此人以来的天数”,您可以通过查找来实现。比方说,您在一个月中的不同人数是(在该月的第 1 天看到的人)+(在第 2 天看到的人,“自上次看到以来的天数”>= 2)+(在当天看到的人)的总和3,“距离上次出现的天数”>= 3)+ ... +(在第 30 天看到的人,“距离上次出现的天数”>= 30)。

方法 1 的明显优点是更简单,但缺点是将所有复杂性都交给数据库本身; 方法 2 的优点是可以快速向您显示您需要的所有值,但会以进一步的 ETL 工作为代价,并且仅限于您添加的措施,不允许任何灵活性; 方法 3 是最灵活的,但代价是 ETL 工作量显着增加,查询更加复杂。

哪种方法是正确的?坦率地说,他们都没有。使用星型模式和蒙德里安来解决这个问题非常棘手。

【讨论】:

就我而言,我总是让用户按日期过滤。在就业事实表中,我只有一个日期(employmentDate)。如果我这样做,那么每个级别(年、月、季度、财政年度)只需 4 个 agg 表就可以逃脱。我是否正确地考虑了这一点?我认为我可以接受缓慢的聚合脚本,或者至少我可以容忍它。 如果用户必须选择一天,他如何才能获得每月的不同计数?还是我们在谈论两个不同的日期维度? 如果用户选择一个月(最低级别是一个月),那么您不会遇到重复计算问题。但是任何超过一个月(多个月、一个季度、一年、多年)的重复计算都会发生。但是,如果我有聚合表,我想我可以解决(季度、年度)问题,但如果它不在行或列轴上,我无法修复多月或多年。 在这种情况下是的,您需要为每个级别使用不同的 agg 表。 谢谢。您的回答很好地解释了为什么这如此令人沮丧,但也让我对什么是可行的,什么是不可行的有了看法。对于人力资源分析来说,这是一个非常普遍的问题,而且真的很痛苦,似乎这应该是更广为人知或讨论的问题。

以上是关于用于处理事实表中的不同计数的聚合表的主要内容,如果未能解决你的问题,请参考以下文章

GraphQl 计数聚合条目

如何根据 OLAP 多维数据集中的度量计算不同的计数

oracle sql中根据其他表中的计数重新启动rownumber

查询用于创建分组、聚合和过滤的行集的不同计数

从同一个累积事实表中分离和独立的计数

如何列出各个列,其中每个列包含一个 id 计数,其中每列中的 id 不在 MySQL 中每列的不同表中