【上篇】模型界的“乌龙事件”:那些年我们踩过的坑在我们上次踩坑历史中,我们共同回顾了在初入模型界时,如何在重重坑点中寻找突破口,并分享了一些宝贵的经验教训。
今天,我们将继续深入探讨那些在进阶阶段遇到的更为复杂且棘手的问题,看看还有哪些开发坑点等着我们,让我们逐一击破,成为数据模型界的“建模大佬”!
踩坑五:错误的基数关系
一个订单系统,每个订单理论上应该能关联多个订单明细记录。
原本关系是一对多,然后手工调整成了多对一:这不仅会导致数据结构混乱,并且订单明细表则失去了独立筛选的能力。结果就是,数据模型就无法真实反映业务的实际复杂性,导致信息丢失。


基数设错了,通常情况下不会报明显的异常错误。
那如何判断基数是否设置正确?
1. 理解业务规则:首先,深入了解各个表之间的业务逻辑。明确哪些实体之间是一对一、一对多或多对多的关系。例如,一个订单可以包含多个订单项,这意味着订单表与订单明细表间存在一对多的关系。
2. 检查字段特征:确定哪个字段作为主键,哪个字段作为外键。外键所在的表应当参照主键表的基数进行设置。
3. 检查数据分布:实际验证一下我们的假设是否站得住脚。执行一些SQL查询来检查外键列的实际基数。如果我们认为[订单表]和[订单明细表]是一对多的关系,可以通过简单的SQL语句来确认这一点。
例如:订单表 与订单明细表,关联字段是OrderID,当订单表的count(*)与count(distinct (OrderID)),是一致的,则认为是“一”的一方;当订单明细表的count(*)与count(distinct (OrderID))不是一致时,则认为是“多”的一方。
同时,该sql也是系统提供自动检测关系功能的原理,也可通过点击检测来确认基数关系是否准确。

目前我们设置关联关系后,系统也会对错误的关联关系进行提示,如将订单明细表与订单表设置为“一对一”后,将会提示:“你选中的基数关系对于此关系无效!”

踩坑六:报表与数据模型一一对应
假设我们正在为一家零售公司构建一个销售分析主题的大屏,需要做以下场景分析:
- 折线图显示各个月份的总销售额变化趋势。
- 地图展示各个省份城市客户的总销售额分布。
- 透视分析展示按产品类别和产品名称分组的销售额明细。


1、踩坑做法
在一个不太理想的方案中,我们可能会看到这样的设计:每一张报表背后直接对应着一个特定的SQL查询,甚至在极端情况下,每一个可视化组件都依赖于其独立的数据模型。这种做法虽然在短期内看似简化了开发流程,但实际上却埋下这些隐患:
(1)扩展性差:当业务需求发生变化或数据源更新时,这种紧耦合的设计使得系统难以进行有效的调整和扩展。任何对现有报表结构或是底层数据库模式的小改动,都可能需要重新编写大量的SQL脚本和数据处理逻辑,增加了维护成本。
(2)无法满足用户自助查询:BI工具强调的是让用户能够自由探索数据,提出自己的问题并获得即时的答案。然而,在上述架构下,由于每个报表或组件都是基于预定义的查询构建的,极大地限制了用户的灵活性和自主性。用户不得不依赖IT部门来创建新的查询或是修改现有的查询,导致响应时间延长,降低了决策效率。

2、正确做法
在理想的设计中,我们推荐采用一种更为灵活和高效的方法:开发一个或少数几个能够支持一类或多类需求场景的数据模型。如下图,我们从需求场景出发,构建一个通用的数据模型即可满足我们看板的查询需求。

强调从整体上梳理各种报表需求的共性,并将这些需求整合到一个综合性的数据模型中。
通过构建通用的数据模型,无论是新增报表、修改现有报表还是调整业务逻辑,只需对核心数据模型进行相应的更新即可。这种设计减少了重复代码的数量,降低了因多处改动而引发错误的风险,同时也使得系统更容易适应未来的变化。它允许用户根据自己的需要自由地探索数据,无需受限于预定义的查询条件,用户可以轻松创建自定义视图和报告,快速获得所需的信息。
踩坑七:数据模型是join关系
初入模型界,我们可能会拿来与旧自助数据集中的join关系对比,常有疑问,数据模型的关系是一方left join 多方为什么有时候它出来的结果不是left join的结果,有时出现非常规逻辑。
这实际上涉及到数据建模的核心理念及其与传统SQL JOIN操作的区别。如下图的业务场景中,我们有如下2个查询需要,传统sql join和数据模型可以如何实现呢:

传统的join:
(1)查询场景1(没有项目的客户也需要查询出来):用客户表left join其他事实表分别做统计。

(2)查询场景2(没有项目的客户不需要查询出来):用事实表 left join 客户表分别做统计。

数据模型:
用数据模型可以表达为下图,设置正确基数关系和筛选方向后即可实现上面的查询场景。而在报表层面我们可以通过开启或关闭压缩空行来显示有无项目的客户。



从上面的例子上面我们可以初步了解,数据模型作为指标体系的内核,期望的是构建一套模型,满足各种用户自助查数的场景,而join满足的都是特定场景的查数意图。传统的JOIN(如LEFT JOIN, RIGHT JOIN等)主要用于满足特定场景下的查询意图,而数据模型则更注重通过定义实体间的基数关系(一对多、多对一、一对一)来灵活响应用户的查询需求。
规则:基于基数的关系设置
非传统JOIN:数据模型中的关系设置并不是简单的LEFT JOIN或RIGHT JOIN,而是基于数据建模理论中的一对多、多对一和一对一关系。
动态构建:当用户选择表字段后,模型的OLAP引擎会根据所选的数据表字段动态构建JOIN关系及相应的SQL语句。这意味着,查询逻辑更加灵活,可以根据用户的具体需求进行调整。
对于数据模型来说,只要基数关系是正确的,就可根据查询意图去动态构建查询,并且保障数据不被放大,因为正确的基数关系,可以让系统统计指标时构建以下规则:以指标所在表为中心,将一方的维度表纳入构成一个扩展表(也可称查询子图,子图概念可在此文中进一步了解:【上篇】99% 的人都忽略了!强大模型的崛起秘密在于设置正确关系),基于这个扩展表的任意查询都可保障结果正确,因为只会纳入一方的维表,所以扩展表指标数据不会被放大或缩小,多方的表只有在启用了双向筛选才会被纳入作为筛选条件,这是基于join关系无法构建的一个规则。
通过本文,我们一同审视了数据建模过程中的种种“乌龙”,包括基数关系的误判到以及传统连接方法的局限。面对这些问题,虽然每一步都充满了挑战,但借助对业务需求的深刻洞察和科学的数据建模策略,我们发现了前行的道路。希望这些经历不仅能帮助你绕过类似的障碍,也能增强你在未来项目中的信心与能力。数据建模的世界总是充满未知,但也正是这些探索使我们的技能日益精湛。
下一期分享中,我们将继续深入探讨更多实用技巧与前沿见解——《数据模型使用迷局:计算列、计算度量,你真的懂吗?》,不见不散!
【有奖互动】亲爱的数据达人们,你是否曾在Smartbi中纠结过该用计算列还是计算度量?这两种看似相似的功能其实大有不同!
我们诚挚邀请您分享:
- 您对计算列和计算度量的理解
- 实际工作中的使用心得
- 踩过的坑和解决方案
精彩回复将获得惊喜麦豆奖励!让我们一起来探讨这个数据分析中的经典话题吧! |