ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

数据仓库建模:ER模型与维度模型的核心区别及选型指南

数据仓库建模:ER模型与维度模型的核心区别及选型指南 1. 项目核心搞懂ER模型和维度模型才算真正入门数仓先说个结论数仓搭建这件事90%的初学者卡住的不是Hive语法不是Spark调优而是建模。而这个建模的核心就是搞清楚ER模型和维度模型到底是个啥以及为什么大家做数仓清一色选维度模型。这期学习笔记就围绕尚硅谷数仓搭建课程里“ER模型和维度模型的概念以及数据仓库为什么选择维度模型”这一段展开把背后的原理、适用场景、选型逻辑讲透最后附上我在实际项目中踩过的坑和总结的判断标准。很多朋友刚接触数据仓库时会有个疑惑我明明已经有业务数据库了MySQL里表建得好好的外键约束、规范化设计都做得漂亮为什么还要再搞一套数据仓库又是什么ER模型、维度模型听着就头大。这个疑惑很真实因为我刚开始也有。后来在真实项目里被业务方追问了几个报表问题才真正理解了业务数据库是给系统用的数据仓库是给人用的。这句话是整个数仓建模的出发点。适合谁看准备入行大数据开发、正在学数仓搭建、或者已经在做报表开发但没系统梳理过建模理论的同学。这篇文章不堆概念我会把ER模型和维度模型拆开揉碎用电商订单这种最常见的场景对比给你看顺便把“为什么选维度模型”这个问题从性能、易用性、扩展性、一致性、交付周期五个角度讲明白。2. ER模型面向业务的规范化建模2.1 ER模型到底在描述什么ER模型全称实体关系模型Entity-Relationship Model1976年由Peter Chen提出是关系型数据库设计中最经典的理论基础。它的核心思路是把现实世界里的业务对象抽象成实体Entity把实体之间的业务联系抽象成关系Relationship最后得到一张抽象的数据结构图。举个最简单的例子电商系统里“用户”和“订单”是两个实体一个用户可以有多个订单这就是一对多关系。ER模型的建模过程就是在回答三个问题系统里有哪些业务对象每个对象有哪些属性对象和对象之间是什么关系这套方法论在业务数据库设计里几乎是无敌的。因为OLTP系统在线事务处理的核心诉求是保证数据的一致性和完整性避免冗余。一个订单明细在业务库里一定是拆分到多张表里存用户信息放user表商品信息放sku表订单主信息放order表订单明细放order_detail表各表之间通过外键关联。这样做的好处是数据只存一份修改一个用户手机号只要update一条记录不会出现多张表数据不同步的问题。2.2 ER模型的三大核心要素与规范化ER模型是建立在关系数据库理论基础上的它的实现过程高度依赖规范化Normalization理论。规范化分几个等级第一范式1NF字段不可再分每个字段必须是原子值。第二范式2NF在1NF基础上非主键字段必须完全依赖主键不能只依赖主键的一部分。第三范式3NF在2NF基础上非主键字段不能存在传递依赖即非主键字段不能依赖于其他非主键字段。三范式是业务库设计的通用标准它从理论上消灭了数据冗余和更新异常。比如在订单表里如果既存了用户ID又存了用户名那么当用户名变更时需要同时更新所有涉及这张表的订单记录这就是传递依赖违反了3NF。正确的做法是订单表只存用户ID用户名字段放user表里通过join去取。这个设计思路在事务系统里极其正确但缺点也很明显查询一张报表可能要关联七八张表。业务库的设计者考虑的是怎么高效地写入和更新压根没考虑过分析师怎么读。所以你会发现直接拿业务库跑复杂聚合查询SQL写得极其痛苦而且性能很差。2.3 ER模型的典型应用场景ER模型最合适的场景就是OLTP系统建设比如电商交易系统后台金融核心账务系统企业内部ERP系统任何需要高频增删改查、强一致性保证的业务系统在这些场景下ER模型的优势是无可替代的。它保证了数据无冗余、无异常事务处理性能好系统结构稳定。这也是为什么凡是从零建设一套业务系统第一件事就是画ER图因为它是系统架构的数据基石。3. 维度模型面向分析的建模利器3.1 维度模型的核心组成事实表与维度表维度模型最早由Ralph Kimball提出它的核心思想完全反过来为了查询和分析的效率刻意保留冗余刻意做反规范化设计。结构上就两类表事实表Fact Table和维度表Dimension Table。事实表是业务过程的度量记录每一行代表一次业务事件或业务事实。比如订单事实表每一行就是一条订单记录包含订单金额、商品数量、运费等可度量的数值字段以及关联维度的外键字段。事实表的特点是行数巨大、增长极快数值字段多文本描述字段极少。维度表是描述业务事实的上下文环境每一行是某个维度的具体成员。比如用户维度表、商品维度表、时间维度表、地区维度表。维度表的特点是行数相对较少包含大量描述性文本字段用来给事实表提供“谁、什么、何时、何地、为什么”等查询和过滤条件。以订单分析为例事实表存订单金额、数量、折扣维度表提供用户等级、商品分类、下单时间、收货省份等信息。要分析“华东地区第一季度VIP用户的订单总额”事实表加上四张维度表的join一条SQL就能清晰写出来。这就是维度模型最直观的价值查询路径短逻辑清晰天然贴合业务分析视角。3.2 两种主流构型星型模型与雪花模型维度模型在物理实现上又分成两种常见构型。星型模型是最推荐的做法事实表在中间维度表围绕在四周每张维度表都直接与事实表关联不做过多的层级拆分。比如时间维度表直接冗余了年、季度、月、日、周而不是再拆一张“季度表”去关联。这样做虽然产生了冗余但查询时只需要一次join就能拿到所有维度信息。雪花模型是星型模型的规范化变体维度表做了进一步的拆分。比如把商品维度表拆成商品表、品类表、品牌表通过外键关联。这样的好处是节省存储空间坏处是查询时要多几次join查询性能下降而且层级变深后SQL的复杂度明显上升。实际工程项目里我之前只在少数特殊场景用过雪花模型绝大多数情况下星型模型都是首选。3.3 维度建模的四步流程维度建模有一套非常成熟的流程也是我在项目里反复使用的套路第一步选业务过程。业务过程是组织关注的业务活动比如“下单”、“支付”、“发货”。一个数据仓库通常覆盖多个业务过程但每个业务过程对应一张或多张事实表。第二步声明粒度。粒度决定了事实表每一行代表的含义是订单行级别、订单级别还是订单明细行级别。确定粒度是建模中最关键的一步粒度越细能回答的问题越多但存储和计算成本也越高。第三步确定维度。一个业务事实会涉及哪些分析角度就上哪些维度。常见的有时间维度、用户维度、商品维度、地区维度、渠道维度、促销维度等。第四步确定事实。事实表里的度量字段包括可加的金额、数量、半可加的库存快照、不可加的比率类指标通常需要拆成分子分母两个字段存储计算时再相除。这套流程走下来一张事实表的设计基本就定型了。它不像ER模型那样要反复做规范化推导而是完全从业务分析需求出发天然面向“怎么查”来设计这是维度模型最大的优势。4. 数据仓库为什么选维度模型五个关键维度的深度拆解4.1 查询性能少关联就是快数据仓库的负担主要是复杂查询、大范围扫描、高并发报表访问这和OLTP完全相反。维度模型把数据在ETL阶段就提前做了加工整合事实表和维度表之间的关联关系是预先设计好的查询时最多三四次join即可完成而ER模型动辄十几次join。很多初学者会问现在ClickHouse、Spark的计算能力这么强join性能早就不是瓶颈了为什么还要在意关联次数这个问题我在实际项目里也遇到过但等我真正跑了一次几十亿行事实表关联几十万行维度表的查询才发现join带来的数据传输量、shuffle开销、内存消耗在集群规模不够大的时候是极其致命的。维度模型的少join设计是从根源上降低计算成本的这和计算引擎本身的性能是两个维度的事。另外维度模型的维度表通常可以直接加载到内存中做广播事实表扫描时直接匹配内存维度数据性能提升非常明显。而ER模型的表结构分散很难做这种优化。4.2 易用性让业务人员能看懂的模型才是好模型这一条我觉得是维度模型最核心的价值却常被技术人员忽视。数仓做出来的最终用户是业务分析师、运营、管理层他们不是程序员不会写复杂的SQL。在ER模型下要分析一个“各品类商品在各省份的销售情况”分析师可能得写出十几行join的SQL还要理解外键关系、理解规范化拆分逻辑难度极大。维度模型把业务视角直接结构化到表设计里了。事实表就是“发生了什么”维度表就是“在什么环境下发生的”。业务人员自己就能看懂星型模型中间是事实周围是维度想筛选什么条件就去对应的维度表里找字段。很多BI工具更是天然支持星型模型的拖拽式分析事实表和维度表自动识别关联业务人员不需要写一行代码就能完成自助分析。这一点就是维度模型和ER模型在“服务对象”上的本质差别。ER模型是给系统用的追求的是数据结构的严谨性维度模型是给人用的追求的是查询路径的可理解性。4.3 扩展性应对业务变化的能力完全不一样业务系统最大的特点就是变化快。新需求、新业务、新分析角度层出不穷。ER模型的应对方式是修改表结构、增加字段、重新设计外键关系每一次变更都涉及一系列连锁调整风险大、周期长。维度模型天生就有很强的扩展弹性。新增分析角度时给事实表增加一个维度外键字段再新增一张维度表就行完全不影响已有表和查询。新增度量值时在事实表里增加一个数值字段即可。这种松耦合的设计让需求迭代的响应速度大幅度提升。这里特别提一下缓慢变化维SCD策略。业务库里的用户等级变了直接update覆盖即可但数据仓库里如果覆盖了历史数据历史报表就全部对不上了。维度模型的应对方案是SCD策略常用三种SCD1直接覆盖不保留历史SCD2增加新记录并标记有效时间和失效时间SCD3增加临时字段保留上一次的值。实际项目中SCD2用得最多它通过增加行而不是改历史行来跟踪变化既保证了历史事实的正确性又能关联到最新维度状态。4.4 一致性统一口径的关键抓手数据仓库里最让人头疼的问题就是口径不一致。同一个“销售额”销售部说是订单金额财务部说是已支付金额运营部说是退款后的净额。这种问题在ER模型下几乎无解因为每个人都可以从不同的业务表里算出不同的数。维度模型通过构建一致性维度来解决这个问题。在数仓建设时先把用户、商品、地区、渠道这类基础维度统一抽取出来做成全公司唯一的标准维度表。所有事实表的关联都必须使用这套统一的维度表。这样无论哪个部门写报表只要用到“商品维度”拿到的商品分类、品牌归属、上下架状态就完全一致。事实表虽然不同但通过一致的维度关联后指标口径自然统一收敛。这里有个概念需要区分一致性维度和一致性事实。一致性维度是几张事实表共用一套维度表保证维度属性相同一致性事实是对于同一度量在不同事实表中的定义和计算逻辑保持一致比如金额字段统一用不含税价。实际项目中一致性维度是数仓建设的重中之重必须在建模规划时统一设计不然后期返工成本极高。4.5 交付周期敏捷迭代的正确姿势大公司做数仓往往是“自上而下”的整体规划从主题域划分到模型设计一步到位。但绝大多数中小企业、创业公司根本没有这样的资源和时间窗口业务每周都在变老板每天都要看新数据这时候追求一次到位的完美模型饿死的概率远大于建模成功的概率。维度模型天然支持“从下往上”的增量式建设。你可以先对一个核心业务过程建模满足当前最急迫的分析需求跑起来之后再逐步增加新的业务过程、新的事实表和维度表。表结构松耦合局部变更不影响全局每一期迭代都能快速交付看得见的价值。这其实就是Kimball和Inmon两种数仓建设方法论之争的核心差异。Inmon主张企业级数仓用规范化模型3NF统一建设保证全局一致性但建设周期长、见效慢Kimball主张维度模型自下而上快速迭代先建数据集市再在数据集市之上做一致性维度整合。现在的业界实践经验证明绝大多数场景下Kimball的维度建模思路更务实这也是国内数仓培训课程里普遍教授维度模型的原因。尚硅谷这套数仓搭建课程也是围绕维度模型展开的看完实战部分就会更清楚为什么不是先画ER图而是直接定义事实表和维度表。5. 实操对比一个电商订单场景说清楚建模差异5.1 场景设定订单和订单明细怎么建表理论讲再多不如实际走一遍建模流程。我用一个电商订单场景来对比ER模型和维度模型的建表差异这个例子也是尚硅谷课程中反复出现的经典场景。假设业务需求是每笔订单包含订单ID、用户ID、下单时间、订单总金额、订单状态、收货省市信息每笔订单包含多个商品项每个商品项有商品ID、商品数量、商品单价需要支持的分析需求有按日期统计订单数和销售额、按省份统计订单量、按商品品类统计销量、按用户等级分析客单价、按渠道分析转化率5.2 ER建模方案按照三范式规范化设计表结构会拆成四张以上用户表user用户ID、用户名、手机号、注册时间、用户等级商品表sku商品ID、商品名称、单价、所属品类ID品类表category品类ID、品类名称、上级品类ID订单主表order订单ID、用户ID、下单时间、订单总金额、订单状态、收货省、收货市订单明细表order_detail明细ID、订单ID、商品ID、商品数量、成交单价要分析“各省份不同品类商品的销售额”SQL大概长这样SELECT o.province, c.category_name, SUM(od.quantity * od.unit_price) AS sales_amount FROM order o JOIN order_detail od ON o.order_id od.order_id JOIN sku s ON od.sku_id s.sku_id JOIN category c ON s.category_id c.category_id JOIN user u ON o.user_id u.user_id WHERE o.pay_status 1 GROUP BY o.province, c.category_name;字段少时还好一旦维度变多比如要加上时间维度、渠道维度、促销维度这张SQL的join数量会直线上升。如果再涉及用户等级的过滤、注册时间的分析还要关联更多表。每一次查询几乎都要全表梳理一遍模型关系维护和理解成本相当高。5.3 维度建模方案换成维度模型后设计流程完全不一样。先确定业务过程下单。声明粒度订单明细行级别。确定维度时间、用户、商品、品类、地区、渠道。确定事实数量、单价、金额、成本。最终表结构变成两张核心表事实表 dwd_order_detail订单ID、用户ID、商品ID、日期ID、渠道ID、地区ID、数量、单价、金额、成本维度表dim_user用户ID、用户名、用户等级、注册日期、手机号、会员类型dim_sku商品ID、商品名称、品牌、品类ID、品类名称、上架状态dim_date日期ID、年月日、季度、星期、是否节假日dim_region地区ID、省份、城市、区县dim_channel渠道ID、渠道名称、渠道类型同样的分析需求SQL变成SELECT r.province, sk.category_name, SUM(f.amount) AS sales_amount FROM dwd_order_detail f JOIN dim_region r ON f.region_id r.region_id JOIN dim_sku sk ON f.sku_id sk.sku_id JOIN dim_date d ON f.date_id d.date_id WHERE d.day 2024-11-11 GROUP BY r.province, sk.category_name;join次数没有减少太多但关键差别在于维度表和事实表的关联关系是固定的、可预判的而且维度表通常只有几万、几十万行完全可以用广播变量缓存到内存中。更重要的是维度表里的字段都是经过清洗、去重、标准化处理的不会出现同一个商品在不同的表里品类名不一致的情况。5.4 两者的本质差异总结用表格来总结这个场景里的差异会更直观对比维度ER模型维度模型表结构高范式拆分表数量多反范式设计表数量少查询难度join多SQL复杂join少且固定SQL清晰面向对象开发维护人员业务分析人员数据冗余极低较高可接受历史变化处理直接覆盖SCD策略跟踪需求响应速度慢变更影响大快松耦合扩展使用阶段OLTP业务系统OLAP分析系统典型代表交易后台、ERP数仓DWD层、ADS层一句话总结业务系统用ER模型保证数据正确性数仓系统用维度模型保证分析高效性两者不是替代关系而是各司其职。6. 常见问题与避坑指南6.1 初学者最容易踩的坑先说几个我在学习和带新人过程里反复看到的坑。第一个坑把维度模型当成ER模型的简化版。有人觉得维度模型就是把表往里塞反正冗余也没关系然后就出现了“一张大宽表打天下”的做法。这是另一种极端。维度模型强调的是事实表和维度表的清晰边界、粒度的明确声明不是无脑冗余。宽表适合特定的汇总场景但作为数仓整体架构是不合适的因为它会破坏一致性维度的复用能力。第二个坑粒度不统一就建事实表。比如订单事实表第一版按订单明细行粒度建第二版因为需求要做订单维度汇总为了偷懒直接也用订单明细表去重再聚合。问题表象是数据对不上根本原因是同一张事实表里混了两个粒度。规范做法是一个粒度的数据一张事实表订单明细一张、订单汇总一张各司其职。第三个坑维度表和事实表之间没有建立清晰的关联关系。有些人在ETL阶段就把维度属性冗余进事实表了比如把商品品类直接写进订单明细表短期看查询方便但一旦品类改名要么改历史数据要么报表口径混乱。正确的做法是事实表只存维度ID由维度表提供属性描述。6.2 数仓分层中的建模适用范围尚硅谷这套课程里数仓分层是经典的ODS、DWD、DWS、ADS四层各层的建模重点完全不同ODS层原封不动同步业务库数据这张表就是业务库的镜像用ER模型的思路去理解它。DWD层核心是维度建模把ODS层的数据清洗、标准化后真实建模是从这一层开始的需要严格按“业务过程粒度维度事实”四步建模产出事实表和维度表。DWS层按主题汇总核心是维度退化比如把用户维度、商品维度直接退化到明细中形成主键少、维度属性多的汇总宽表。ADS层面向具体业务需求的应用层一切以查询效率为先这里反而可以大胆使用宽表、临时表。理解了这一层你就明白了为什么说“数仓为什么选维度模型”这个问题的答案要分阶段回答DWD层用维度模型打基础DWS和ADS层是在其之上的汇总和应用。6.3 讲一下维度表的设计细节维度表设计有几个细节值得单独说。一是代理键的使用。维度表的主键不要直接用业务系统的ID而是生成一个自增的代理键。为什么要这样做因为同一个业务ID可能对应多条历史记录SCD2业务ID无法唯一标识一行。代理键与业务解耦保证事实表关联的是唯一确定的维度行。二是维度属性的覆盖度。维度表不是简单搬运业务表字段要把分析可能用到的角度全部考虑进去。比如用户维度业务表里只有手机号、注册时间、等级但分析时需要年龄、性别、城市、会员来源、最近活跃时间等这些需要通过ETL加工或外部数据补充。维度表设计得越完善下游分析时的灵活度就越高。三是日期维度的处理。日期维度几乎是所有事实表都必需的维度通常预生成未来5到10年的日期数据包含年、季度、月、周、工作日标记、节假日标记等。很多初学者不重视日期维度分析排序、周同比、节假日营销效果时才发现没有预置字段临时补非常痛苦。6.4 什么时候可以破例用ER模型维度模型虽然好但也不是放之四海而皆准。有几种场景我会破例使用ER思路数仓的ODS层本身就是原样同步业务数据。数据集市之间的数据整合如果对企业级一致性要求极高且业务相对稳定、分析需求偏固定用3NF建模可以提供最干净的底层数据治理能力强。一些复杂的金融、财务类分析对口径和血缘要求极高ER模型的严格规范化能够减少口径歧义。但即便在这种场景下我的经验也是核心要还是用维度模型只在风险高的局部使用ER思路。毕竟绝大多数BI分析和报表查询都是面向业务过程的多维分析维度模型的优势在效率、易用性和交付速度上是压倒性的。7. 课程学习路线与实战建议7.1 尚硅谷数仓搭建课程里的建模知识怎么学如果正跟这套课程学习我给一条建议不要把“ER模型和维度模型”这一节当理论课跳过去。虽然它听起来像一堆概念但它是整个数仓实战项目的灵魂。后面所有DWD层的建表语句、维度表的设计、事实表的加工逻辑都是顺着这一节的核心思路走的。碰到疑惑时动手跑一遍课程里的SQL把订单表相关的ER建模方案和维度建模方案都写出来对比一遍感受完全不同。我在学习时专门画了一张对比图把同一个订单业务在两种建模方式下的表关系画出来作用比看十遍视频都大。7.2 结合课程的实战练习建议如果能抽出额外的时间建议找一个开源的数据集或自己造一批模拟数据独立完成一遍完整建模第一步从订单流水和用户信息出发画出ER图。第二步定义业务过程、粒度、维度、事实设计维度模型。第三步分别在MySQL里建ER结构的表、在Hive里建维度模型的表各写三条分析SQL体验区别。第四步给用户表增加一个“等级变更”场景实践SCD2策略观察历史维度的变化。这四步做完比刷十遍课程视频更能形成肌肉记忆。建模这件事本质上是思维方式训练面对同样的业务事实ER模型问的是“怎么存”维度模型问的是“怎么查”你只有亲手做过两种方案才能真正理解为什么业内主流答案是维度模型。7.3 一个能直接用的建模自检清单最后分享一个我从实战里总结出来的清单每设计一张事实表前过一遍这个业务过程的粒度是什么是否唯一这张事实表需要哪些维度是否都有对应维度表维度表是否使用代理键是否做了SCD策略规划事实表的度量字段哪些是可加的哪些需要特殊处理事实表和维度表的关联是否清晰下游查询最多几次join维度表的属性是否覆盖已知分析需求是否预留了扩展空间是否存在口径歧义的风险是否需要建立一致性维度这张表在DWD、DWS、ADS哪一层它的消费方是谁这几个问题如果能全部答上来说明这一章的建模思路你真正吃透了。8. 学习这段内容的实际体会最后说点题外的经验。跟着课程学数仓搭建时这个章节看起来最简单无非两个概念嘛但恰恰是这最基础的东西决定了后续项目能不能落地。我在实际工作里见过不少人Hive语法写得很溜却因为建模混乱导致指标对不上、需求改不动最后整个数仓推倒重来。这个代价远比多花一周时间搞懂维度模型要大得多。还有个小技巧学习时不要只盯着“数据仓库为什么选择维度模型”这个结论多问几个“为什么不选ER模型”为什么不直接用业务库表为什么不用宽表为什么不用雪花模型每个为什么的背后都是一次对数据仓库本质特征的理解加深。数仓搭建这条路算法可以慢慢积累工具可以边用边学但建模思维必须一开始就建立正确。ER模型和维度模型不是一个孰优孰劣的问题而是在不同场景下怎么选才最优的问题。搞懂这个你再看数仓分层、ETL设计、指标体系建设都会有柳暗花明的感觉。
返回列表