4

我正在构建一个模型以允许报告两个单独的数据集,对于这个例子,我们会说一个学生数据集和一个员工数据集。

数据集非常独立,两者之间唯一真正的联系是日期,所以从模型的角度来看,有一个学生星模式和一个员工星模式。

显示的数据是快照类型的数据,回答如下问题: - 对于选定的日期,显示所有在职员工 - 对于选定的日期,显示所有已注册的学生

This means that when a single date is selected, the model then finds all employees where the selected date falls within the employment start & end date , and finds all students where the selected date falls within the enrolled start & end date.

这意味着我必须做出决定,如何使用单个日期维度从每个模式返回正确的数据。创建关系将不起作用,因为表格中的关系不允许“之间”类型的查询,因此我有一个不相关的日期维度,并且每个模型的 Dax 都会找到适用的行。

问题是它不是性能最好的。对于可能 50k 行,添加一个度量可能需要 5-10 秒。

我问是否有更好的方法来编写查询或更改模型以仍然让我进行“介于”样式查询但提供更好的性能。

下面是一个 dax 查询示例,用于返回在特定日期注册的所有学生。

感谢您的任何建议。

All Enrolled Students:=IF (
HASONEVALUE ( 'Date'[Date] ),
CALCULATE (
    DISTINCTCOUNT ( 'Students'[StudentID] ),
    FILTER (
        'Students',
        'Students'[StudentStartDateID] <= MIN ( 'Date'[DateID] )
            && 'Students'[StudentEndDateID] >= MAX ( 'Date'[DateID] )
    )
),
BLANK ())
4

2 回答 2

1

这种类型的场景通常称为“正在进行的事件”或“有持续时间的事件”。看看下面的链接。答案将取决于您的 SSAS 版本和事件持续时间长度。

https://www.sqlbi.com/articles/analyzing-events-with-a-duration-in-dax/ https://www.sqlbi.com/articles/understanding-dax-query-plans/ https:// blog.gbrueckl.at/2014/12/events-in-progress-for-time-periods-in-dax/

如果这些措施表现不佳(这可能发生在持续时间较长的事件中),则可能需要为事件的每一天生成一个包含一行的表。SQL 看起来像这样:

SELECT        
   d.CalendarDate      
  ,s.StudentID
FROM dbo.Students AS s 
CROSS JOIN dbo.DimDate AS d      
WHERE d.CalendarDate >= StudentStartDateID      
AND d.CalendarDate <= StudentEndDateID

创建从此表到日期/日历表的关系。

通过这种设计,您可以使用一个简单的 DISTINCTCOUNT(Students[StudentID]) 度量,它应该表现更好。代价是这个表可能会变得非常大。保持它尽可能窄,以获得最佳性能和内存保护。另一种优化可能是使用不同的粒度,例如周或月而不是天。

于 2017-11-03T14:55:53.020 回答
1

在某些情况下,不相关或“断开连接”的表非常适合为切片器、时间线和过滤器供电。正如您在问题中所说,您有两个优化选项:重新构建数据集优化现有的度量语法

重构数据集

在开始日期和结束日期之间的每一天复制每一行,并为该迭代日期提供一列。这可以通过多种方式完成,具体取决于您获取数据集的方式,但可能很乏味。然后,在此迭代日期关联您的表,并使用该关系从 DATE 过滤到 FACT。如果这是一个定期报告和/或您正在使用 SQL 来提取数据,那么利用 PowerPivot 的关系计算能力可能是值得的。

优化 DAX 语句

如果这是一次性请求,或者数据集太繁琐而无法按天复制,那么坚持使用断开连接的表方法并清理度量语法。由于您已经包含了 MIN() 和 MAX() 函数并且 CALCULATE() 返回 DISTINCTCOUNT(),因此不需要条件 HASONEVALUE() 函数。我在模拟环境中运行它并取得了不错的结果,但这可能会因计算机性能和数据集大小而异。请参阅下面的清洁语法。

All Enrolled Students:=CALCULATE (
    DISTINCTCOUNT('Students'[StudentID]),
    FILTER(
        'Students',
        'Students'[StudentStartDateID]<= MIN('Date'[DateID]) &&
        'Students'[StudentEndDateID]  >= MAX('Date'[DateID])
    )
)

如果您的 StudentID 列是唯一的,这对我来说很有意义,您可以进一步加快速度。

All Enrolled Students:=CALCULATE (
    COUNT('Students'[StudentID]),
    FILTER(
        'Students',
        'Students'[StudentStartDateID]<= MIN('Date'[DateID]) &&
        'Students'[StudentEndDateID]  >= MAX('Date'[DateID])
    )
)

如果 StudentID 不是数字,则将 COUNT() 替换为 COUNTA() 以获得所需的效果。

于 2016-09-09T13:58:38.223 回答