快速变化维(QCD)是相对于缓慢变化维(SCD)而言的,像【会员维度】里的【会员级别】这类变更不是很频繁的维度属性就属于SCD,而像【年龄】、【最后交易日期】这类变更频繁的维度显然不能以SCD的思路去解决问题,SCD能处理的维度通常都在oltp库里通常会做Change_Log,例如会员升级降级的时间点会在生产库做记录,但像【年龄】、【最后交易日期】这类维度如果也在oltp库做记录很快就会维度表爆炸,说到这里看官可能会对年龄这个维度有些疑问:为什么不用交易表里的交易时间来算“当时年龄”呢?不要着急,这里先要明确两个概念:【当时年龄】和【交易年龄】,如果要对这两个维度归类的话,后者【交易年龄】应该归为【交易维度】,而前者【当时年龄】是要归为【会员维度】的,【交易维度】里的【交易年龄】只能用来分析交易事实(例如分析交易是由哪些年龄段的会员产生的),而【会员维度】里的【当时年龄】是要能同时分析交易事实和会员事实的,就是说使用这个维度不只是能分析某年龄段的会员产生了多少交易量,还要能分析某年龄段的会员人数(不是每个会员都会有交易产生)。这个问题可以延伸到SCD里用代理键去关联维度表和事实表后能做哪些分析,同样的道理,如果【会员维度】是通过代理键和【交易事实】产生关联,那么再使用【会员维度】去分析【会员事实】就不那么容易了(主要是性能会打折扣),因为这时候【会员维度】的唯一标识已经不是account_id而是代理键,但【会员事实】要做的分析是distinct account_id而不是distinct 代理键,好吧,有点跑题了,还是继续聊QCD吧。既然不能像SCD一样把变更历史都持久化,又希望能以UDM的思维方式去实现Self-Service BI,有没有什么好的思路在SSAS里解决这类分析的效率问题呢?我的答案未必适合所有人,但如果能对你有那么一点启发也是非常有意义的事情,或者你有更好的方案也不妨一起讨论下。
我们先来看看传统BI写sql是如何做此类分析的,首先明确一点,oltp库上只有每个会员的【会员生日】、每笔交易的【交易时间】这样的信息,对sql来说也的确不需要其它额外的信息了,通常是要先对会员做个时间点的快照,使这类会员维度信息回溯到这个时间点去,比如说用户想要分析2014-01-01这一天的【会员人数】、【交易人数】、【交易金额】三个事实度量值,并按2014-01-01这天的【会员年龄】分组统计,那么这段sql脚本必不可少是要输入一个日期参数并指定为2014-01-01,然后根据这个日期参数以及【会员生日】、【交易时间】去做当天的会员快照以得到当天所有会员的【会员年龄】和【最后交易日期】等维度信息,然后再左关联交易表去做聚合分析,思路大致如此,具体实现因人而异。
现在我们回到SSAS,可不可以利用上面这个思路去做一个【会员快照维度】呢?用户自己随意指定一个日期,并命令ssas process update这个【会员快照维度】生成这个日期的会员快照,里面包括所有类似【会员年龄】、【最后交易日期】这样的快速变化维,甚至想【会员级别】这类SCD的属性也可以放进去,维度表的key还是account_id,这样就能保证和【会员事实】、【交易事实】同时产生关联,我的实现正是如此,因为我的客户选择的BI Tool是excel,所以一切就水到渠成,只需要用vsto做一个插件功能,给用户指定需要做快照回滚到的日期并提交
服务端收到命令后,只是简单的process update这个【会员快照维度】即可,而这个维度表对应的数据源是一个function,之所以没用view,是因为view不支持传参
ALTER FUNCTION [dbo].[f$DimPeriodAccount] ( @UDP varchar(100) ) RETURNS TABLE AS RETURN ( ................. )
图上看到我做了两个【会员快照维度】,在做会员身份变更分析时会非常有用,比如说要分析2013-01-01这天的普通会员在2014-01-01这天有多少升级成金卡,有多少升级成钻石卡了,以及每个Group Target的交易事实。
这是目前权衡性能和用户体验后,我能找到的最合适的方案,拿出来抛砖引玉给大家拍砖讨论吧