本文的设计方法主要应用于大型综合数据分析系统,由于其接入数据源种类较多且数据不稳定。所谓不稳定是指数据进入数据仓库后,外部数会发生变化,关键是这些变化会影响整体的数据分析。一般的数据仓库中采集的各种数据聚合策略,聚合后的数据能够提升整体的分析效率,但聚合后的数据更新的成本极高,会产生链条式的反应,影响一波又一波的数据。双外键的设计主要是应对这类不稳定的数据源,针对数据来源多样化、数据源无法受到自身约束的数据分析系统。
关系型数库中有所谓的主键,外键,这些都是数据库基本的特性,也统称为关系键。通常,关系键用来表示领域模型中的关联关系,这也是最常见的使用方法,而本文讨论的关系键的使用与之不同,是在特定的场景下对关系键使用,这样的场景也会在不同的应用系统中出现,所以本设计方法应该具有普适性,适用于各数仓的模型设计。
我们先简化零售系统中的领域模型,只存在三个模型:门店、导购和订单,如下图所示:
综上所述,传统的关联外键的设计是无法解决数据在数仓中的唯一性,同时也无法确保业务主键发生变化后,数据统计和检索的一致性。我们需要一个新的设计方法,既可以保证数据的一致性,同时对数据变更量达到最小。
首先,我们先理解一下事实数据的概念,事实就是事实 ,永远都不会改变,所有的事实数据关联的都是一个稳定的维度数据。而且需要真实的描述事实,体现出数据的变化,此时,针对真实的描述和稳定的关联,本文引出了两个重要的概念:
文字型的描述不够直观,但仔细阅读能够理解的更透彻,下面我们通过真实案例分析双关联键的原理:
上图中门店表shops 中存在两个code,分别为code 与assoc_code,当数据不发生变化时,两个字段的值保持一致,一旦发生code 变更后,旧记录的 assoc_code 字段值则与新记录的code 保持一致,主要用于数据分组及过滤; 1)hashed_id 与shop_id 两个字段的生成规则一致,均为farmHash(shop_id),如果存在多个主键,则拼接后再hash 2)上图描述了门店表shops 与订单表orders 之间的关联关系,以hashed_id 与shop_id 为主外键关系进行关联; 3)门店表下方的0003 的门店为数仓表中的新增记录,而应用系统中则是门店 0002 的code 变更为0003; 4)订单表orders 表下方的数据为门店编码变更后产生的新的订单数据,所以shop_id 与新门店的shop_id 进行关联;
基于上述表结构的设计,维度表shops 中分别存在两个业务主键code,而维度表shops 与事实表orders 关联则用hash 后的数值进行关联,而该hash 值由业务数据生成,具有业务特征,即使误操作后,导致数据丢失也不会影响数据的关系。实际的查询示例如下:
SELECT t1.assoc_code, t1.name, COUNT(DISTINCT t2.no), SUM(t2.amount) FROM shops t1
LEFT JOIN orders t2 On t1.hashed_id = t2.shop_id
GROUP BY t1.assoc_code, t1.name
上述查询按门店进行分组,统计订单数量和销售金额,在这样的设计,可以确保应用系统的数据变更后,数仓中的数据变化最小,维度数据的变化,相比事实数据的变化容易的多,这样的设计也可以应用到聚合模型的设计中,可以对历史数据按天,按月的形式聚合,但需要注意的是hash_id 的设计需要增加相应的维度,否则会产生笛卡尔积内的数据重复,导购统计结果的错误。
双外键的设计有两个关键的特点:1)同一个外键存储了两份,一份用于记录历史,而另一份用于响应变化,并提供对外检索和分组的能力;2)维度表与事实表之间的关联以带有业务特征的hash 值进行关联,而不是自增的无意义的数据进行关联,这样的好处是,数据无论产生任何变更后,关联关系依然有效,而且数据进入数仓的先后顺序可以随机,对采集系统的设计可以非常灵活。
这样的模型设计充分解决数仓数据的灵活性,也降低外部系统的变化对数仓数据的影响。尤其对数据聚合模型产生的影响比较深远,通常大数据存储的数据聚合后是无法进行修改,但实际场景中维度数据的变化是无法避免的,这就要求数仓的模型设计能够兼容这样的场景,当前很多的大数据系统基本是通过重新计算的方式来解决,或者人肉的方式解决,因此,双外键的设计将有效提升数据系统的灵活性和可用性,降低对外部系统的要求,从而提升开发效率。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。