作者回复: 你好,感谢你的留言。 面向对象编程强调封装和继承,而关系型数据库强调规范化和解耦,这两种思想其实是有冲突的。这就是为什么我们经常遇到 ORM(对象关系映射)问题。你提到的“把关系看成对象处理”,可能指的是对象关系数据库或 NoSQL,但这和数据仓库的维度建模、宽表模型并不是一回事。 我来解释一下维度建模和宽表模型。 维度建模是 Ralph Kimball 提出的数据仓库设计方法,核心思想是把业务过程抽象成“事实表”和“维度表”。 事实表记录业务活动的度量值,比如销售额、订单数量,通常很大。维度表记录上下文信息,比如时间、地点、商品、用户,相对较小但描述信息丰富。 举个例子,分析电商订单数据时,订单事实表包含订单金额、商品数量等度量值,关联时间维度表、用户维度表、商品维度表、地区维度表等。查询“2024 年 11 月北京地区的销售额”时,通过事实表关联时间和地区维度即可。这就是星型模式,查询时可以灵活地从不同维度分析数据。 宽表模型则是把事实表和多个维度表通过 Join 合并成一张大表。所有分析字段都在一张表里,查询时不需要再做 Join,速度更快。 还是订单的例子,宽表会把订单金额、商品数量、下单时间、用户姓名、用户地区、商品名称、商品类别等所有字段放在一起。优点是查询性能好,缺点是存储成本高,维度信息会重复存储,维护成本也更高。 在大数据场景下,宽表非常常见。因为大数据系统采用列式存储,对宽表支持好,而且大数据分析更关注查询性能。很多 OLAP 引擎,比如 ClickHouse、Doris,都对宽表做了很好的优化。 简单说,维度建模是逻辑设计方法,帮我们从业务角度理解和组织数据;宽表是物理实现方式,为了提高查询性能而做的优化。实际项目中,通常先按维度建模思路梳理事实和维度,建立规范的数据仓库分层,然后在应用层根据查询需求创建宽表来提升性能。 数据建模的本质是对业务的理解和抽象,无论关系模型、维度建模还是宽表模型,都是为了更好地组织数据,服务于业务分析。 希望这个解释能帮助你理解。如果还有疑问,欢迎继续交流。
作者回复: 你好,感谢你的回答,能看出你不仅有丰富的实践经验,更难得的是你对这些经历进行了深刻的反思和总结。 关于思考题一,你们数仓建设的这段历程非常有代表性。 第一版“基础-应用”模式,所有逻辑由分析师自行决定,导致同一指标在不同报表中不一样,这是缺少统一数据模型和指标管理的问题。每个分析师按照自己的理解去计算指标,必然会出现口径不一致的情况。这也是为什么专门强调了指标管理体系的重要性。 第二版尝试引入标准分层,但由于共同开发导致混乱,我觉得主要还是由于职责不清。数据开发和数据分析是两个不同的角色:数据开发应该负责构建稳定、规范的数据模型,关注数据的可复用性、一致性、性能;数据分析师应该基于这些模型去做灵活的分析,关注业务洞察。当混在一起做同一件事,就容易出现你说的那种混乱。最后选择由数仓开发统一来做是正确的。数据仓库的建设必须有统一的架构设计和规范约束。当然,不是不听分析师的需求,而是要建立一个机制,让分析师的需求经过梳理和抽象后,转化为规范的数据模型。 “增量任务让开发人员不屑于花时间了解,做成了一个数据表对应一个明细表,没有做整合”,这个问题的本质是缺少持续的技术规范和代码审查机制。 我想分享几个应对建议:建立数据模型的设计评审机制;引入代码审查机制;建立技术债务的定期清理机制;通过元数据管理系统来辅助。 “开发人员绷着的弦儿懈怠下来后很难再次绷紧”,这个观察非常深刻。这也是为什么在课程中我反复强调规范、流程、机制的重要性。好的系统不应该依赖于人的责任心,而应该让做正确的事情成为自然而然的选择,让做错误的事情会被及时发现和纠正。 关于思考题二,外卖平台的数据建模思路很清晰。 核心实体包括客户、骑手、商铺,这是正确的。业务过程的梳理也很准确,用户浏览搜索、下单、取餐、配送、完成,这是完整的业务链路。 商铺分类、商铺、菜品可以形成下钻的维度层级,这个思路很好。在实际建模中,这三个可能会设计成一个雪花模型,商铺分类是一级维度,商铺是二级维度,菜品是三级维度。也可以做成一张退化维度的宽表,把三级信息都放在一起,具体取决于查询模式和性能需求。 关于事实表的设计,你提到了两个主要的业务过程:下单销售和取餐送餐。这是对的,在实际的外卖业务中,可能需要更细粒度的事实表。比如,订单事实表,记录每笔订单的金额、商品数量、下单时间、优惠金额等,这是最核心的交易事实表;订单明细事实表,记录订单中每个商品的详细信息,用于分析商品级别的销售情况;配送事实表,记录每个订单的配送过程,骑手、接单时间、取餐时间、送达时间、配送距离等,用于分析配送效率。实际建模时,要根据业务的分析需求来确定需要哪些事实表,以及每个事实表的粒度。 “同时夹杂类似于物流结果的展示,比如已送达等”,这里涉及到一个重要的建模问题:状态的处理。订单有多个状态,已下单、商家确认、骑手接单、配送中、已送达、已取消等。这些状态如何在数据仓库中建模,有两种常见的方式。 一种是快照事实表,每天或每小时对所有订单的状态做一个快照,记录每个订单在这个时间点的状态。这样可以方便地回溯历史状态,但缺点是存储成本高,每次快照都要保存所有订单。 另一种是累积快照事实表,一个订单一行记录,但这行记录会随着订单状态变化而更新。记录订单生命周期中每个关键节点的时间,下单时间、商家确认时间等。这样一行记录就包含了订单的完整生命周期,方便计算各个环节的时长。 在实际项目中,这两种方式可能会结合使用,取决于具体的分析需求。 关于思考题三,“支持非结构化数据原始存储与向量化存储”,这个方向是对的。 在大模型时代,我们需要处理越来越多的非结构化数据,比如评价文本、菜品描述、客服对话记录、骑手的语音反馈等。这些数据如果要被大模型使用,需要先转换成向量,也就是 Embedding。在后面的课程,我们会详细讨论大模型时代的数据处理。 “目前在实践中 AI 还停留在 dify 搭建工作流阶段”,这是一个很好的起点,可以快速体验和验证 AI 的能力。这个过程中,你可以观察 AI 需要什么样的数据,数据以什么形式提供效果最好,这些都会对未来设计支持 AI 的数据架构有帮助。 可以尝试一些具体的场景。比如,把数据仓库的元数据,表名、字段名、业务含义等,用 Embedding 转换成向量,存到向量数据库中。然后用自然语言去查询,“哪些表包含订单金额信息”,通过语义搜索找到相关的表。再比如,如果你们有用户评价数据,可以用大模型做情感分析或主题分类,把非结构化的评价文本转换成结构化的标签,然后存入数据仓库,这样就可以用传统的 SQL 去分析了。这些小的实践,会帮助你逐步建立起 AI 和数据仓库结合的感觉。 数据仓库建设不仅是技术问题,也是管理问题、文化问题。需要持续投入,持续优化,持续宣贯。期待你在后续的学习和实践中继续分享你的经验和思考。