拓冰建站拓冰建站
首页 / 资讯中心 / 正文

DWS层建设实战:从主题域划分到指标口径统一

1. DWS层到底解决什么问题搞数仓的人应该都有过这种经历业务方一句“我要看昨天全渠道订单数”听起来很简单但真去落地的时候你会发现自己要面对一堆乱七八糟的数据源订单在交易库里是一张表在退货系统里是一张表在售后系统里又是另一套逻辑。如果直接把原始数据扔给报表那你每天就是在给业务方擦屁股口径对不上、数据对不齐、跑数跑到半夜还被催命。真正让我意识到DWS层价值是一次做活动复盘的数据运营要对比双11当天每个小时的全渠道GMV和去年同期对比如果直接从明细层去算光是扫描的数据量就够喝一壶而且每个指标得重算一遍业务等三小时还拿不到数。那之后我下定决心不管项目多紧DWS层必须建而且要建扎实。很多人会把DWS层简单理解成“汇总表”或者“宽表层”其实没那么简单。DWS全称是Data Warehouse Summary数据汇总层它处在DWD明细层和ADS应用层之间核心职责是面向主题做汇总。它不是简简单单把count和sum的结果放一张表里而是要承接整个数仓的指标复用、口径收敛和性能优化。可以这么理解DWD层是把数据洗干净的“原料库”DWS层是厨师提前备好的“半成品”ADS层是根据顾客口味现炒的“成品菜”。你不可能每个客人点菜都从杀猪开始对吧DWS层就是那个把常用食材提前切好、腌好、配好料的中央厨房客户点单的时候你只需要开火下锅几分钟就出餐。这篇内容适合正在做数仓分层、准备把DWS层建起来或者建了DWS但总觉得“差点意思”的朋友。我会把这几年在DWS层建设过程中踩过的坑、沉淀下来的设计思路和实操细节一次性讲透不讲空泛的概念全部是可以用到项目里的东西。1.1 先看数据链路里DWS的位置很多数仓团队一开始是没有DWS这个概念的。最原始的做法是ODS收集原始数据然后一张大宽表算完所有指标再推到报表中间的DWD和DWS两层往往被合在一起或者干脆省略。这样做的后果很明显每张报表都是独立烟囱同一个用户数报表A统计口径是“注册用户表的count”报表B是“订单表里去重user_id”两边差一大截业务方开会的时候你拿什么解释DWS层之所以被放到DWD之上、ADS之下就是要在中间形成一个“稳定沉淀带”。DWD解决数据怎么洗干净、怎么标准化DWS解决指标怎么按主题汇总、怎么让上层复用。链路大概是ODS落地原始数据DWD完成清洗、去重、维度退化、主子表打平DWS按业务主题做轻度汇总把高频使用的指标和维度组合沉淀成表ADS基于DWS做灵活查询和报表输出。DWS做得好不好直接决定了ADS的效率也决定了业务方能多快拿到数。我记得项目上线初期由于DWS层表设计太粗糙每次新需求一来开发就得回到DWD层重新聚合一个需求两三天后来我们花了两周时间把DWS层重构了一遍从那以后新报表需求的开发时长降到了一天以内效果立竿见影。这个位置不是随便放的它是整个数仓性能与复用的“胜负手”。1.2 DWS层存在的三个理由有人会问如果明细层DWD已经标准化了我每次查询直接写SQL做聚合不就行了为什么要多一层汇总这类问题我太常听到了不能怪提出疑问的人因为如果数据量不大、指标不多确实可以这么干。但一旦业务复杂起来你很快就会发现没有DWS层的数仓根本跑不动。第一个理由是复用。像“曝光人数”、“加购人数”、“支付人数”这种指标不是某一个报表要用而是全公司无数张报表、无数个自助分析都要用。如果每次都从明细层现算10个报表就要算10遍DWS层把这种高频汇总结果落地后续任何一个消费方都直接基于DWS取数开发量指数级下降。第二个理由是口径收敛。口径不统一是数仓最大的内耗来源DWS层集中管理指标的汇总逻辑同一指标的SQL只维护一份谁要数都从这一份逻辑取从机制上杜绝了“各写各的、各算各的”的现象。第三个理由是性能。明细层的数据量动不动就是几十亿行直接往上抛给报表查询延迟高到没法看而DWS层通过预先聚合大幅减小数据量报表查询从分钟级降到秒级这个体验差距是质变。所以DWS层不是一个可选项而是数据规模上去之后的一个必选项。你前期可能觉得多写一层很麻烦但后期你会发现这一层才是整个数仓稳定和高效的核心枢纽。2. 主题域划分先把“饼”画对DWS层建设的起点绝对不是直接拉几张宽表而是要先做主题域划分。主题域这个词听起来挺悬其实就是把企业业务按照“关注视角”切成几大块每一块就是一个主题后续所有的汇总表都归到对应的主题下面。主题域划分的合理性直接影响DWS层后续的可扩展性和易用性这个决策很难推翻重来所以一开始就要想清楚。我见过有人在主题域划分上特别随意完全按照部门来定比如“运营部主题”“产品部主题”“市场部主题”这种划分方式用不了多久就崩了。因为部门是会变的一个业务可能横跨多个部门一个部门也可能负责多个业务边界模糊后续建表归属就会混乱。正确的做法是从业务过程出发划分主题域。2.1 从业务过程出发而不是从部门出发业务过程就是业务中发生的“事件”比如用户下单、用户支付、商品上架、退款完成、用户登录、用户注册这些都是业务过程。主题域划分要围绕这些业务过程来组织才能保证每个主题域内部的业务是高内聚的主题域之间是低耦合的。举个实际例子如果你是做电商的你大概会分出这么几个主题域交易域下单、支付、退款等交易链路、流量域曝光、点击、访问等用户行为、用户域注册、登录、资料完善等用户生命周期事件、商品域上架、下架、库存变更等商品生命周期事件、营销域活动参与、领券、核销等营销事件。每个主题域再拆成多个“业务过程”比如交易域下面有“下单”、“支付”、“退款”三个过程然后每个业务过程再结合维度组合生成汇总表。这样做的好处是当业务方问“这个月交易情况怎么样”你可以直接定位到交易域很快找到对应的汇总表当有新需求进来你也能快速判断该在哪个主题域里面去扩展而不是推倒重来。这里有一个原则值得反复强调宁缺毋滥先小后大。一开始不要试图覆盖所有可能存在的主题域先把核心的、稳定的业务过程纳入进来留好扩展位。我见过一开始就把主题域设计得非常细的团队结果很多主题域下面根本没数据反而增加了维护成本得不偿失。2.2 实际划分案例演示拿我实际做过的一个电商类数仓项目来说最终沉淀下来是五个主题域。交易域是核心覆盖订单下单、订单支付、订单退款、订单完成四个业务过程其中订单支付的数据量最大、使用频率也最高所以我们为它单独设计了支付明细汇总表粒度是“支付时间 用户 商品 店铺 省份 支付方式”每天一个分区。流量域覆盖曝光、点击、页面浏览三个业务过程原始埋点日志量极大数据清洗后进入DWD再汇总成一张“流量行为汇总表”主要用于用户行为分析和转化漏斗分析。用户域覆盖注册、登录两个业务过程汇总表主要服务于新增用户分析、活跃用户分析、用户留存分析。商品域覆盖商品上下架、库存变动这个域相对轻量但却是采购和运营团队的高频查询对象。营销域覆盖活动参与、领券、核销电商大促期间这个域的查询量甚至能超过交易域因为运营实时盯着各种营销活动的效果。| 主题域 | 业务过程 | 核心汇总表 | 主要服务对象 | | 交易域 | 下单、支付、退款、完结 | 交易明细汇总表、订单生命周期表 | 运营、销售、财务 | | 流量域 | 曝光、点击、浏览 | 流量行为汇总表 | 用户增长、产品 | | 用户域 | 注册、登录 | 用户注册汇总表、活跃汇总表 | 用户运营、BI | | 商品域 | 上下架、库存变动 | 商品生命周期汇总表 | 采购、供应链 | | 营销域 | 参与、领券、核销 | 营销活动汇总表 | 活动运营、市场 |这个结构并不是一开始就全部设计好的前两个月只有交易域和用户域后来随着业务发展逐步加了流量域和营销域。主题域的好处是新增域不影响原有域的建设非常容易扩展。2.3 主题域划分的三个避坑点第一个坑是把主题域和报表混为一谈。有人会问既然运营每天看“各省销售报表”那我建一个“区域主题域”不就行了这种思路就是典型的报表思维区域只是一个维度不是一个主题域应该作为交易汇总表的维度出现而不是单独成为一张表。要是按报表分主题域报表数量一多主题域会变得无穷多DWS层最后跟ADS层没有任何区别。第二个坑是粒度不一致导致表没办法join。交易汇总表的粒度如果是“天 用户 商品”那它的度量可以支持任意维度的上卷查询如果你某个汇总表的粒度是“天 店铺”那它就没办法跟“天 用户”这张表在统一粒度上做关联分析。我在实际项目中就被这个问题坑过交易域的表和用户域的表join之后数据翻倍排查了半天发现是两张表粒度不同一个到用户、一个到店铺。所以设计每张汇总表之前第一件事就是明确它的粒度而且同主题下的表粒度尽量保持一致或保持倍数关系。第三个坑是疯狂加“新主题域”来掩盖设计不足。有时候一个新需求来了其实只是原有主题域加一个维度或者加一个度量就能搞定但因为对原表不熟悉就图省事建一个新域新表。久而久之DWS层表数量爆炸元数据管理混乱数据血缘变成一团乱麻。记住主题域是稳定的框架如果发现经常需要新增主题域大概率不是业务发展太快而是当初的设计没做透。3. 模型设计明细汇总和派生汇总两条腿走路主题域划完之后进入DWS层建设的主体环节模型设计。这块我是吃了不少亏才慢慢摸索出门道的。很多网上资料讲DWS概念一大堆真到自己上手写建表语句的时候还是不知道该建几张表、表该怎么设计。我这里不念概念直接说我最常用的两套模型明细汇总型和派生汇总型。3.1 什么是明细汇总型DWS表明细汇总型DWS表简单说就是“把DWD明细表按常用维度提前group by一遍”。比如DWD层有一张“订单支付明细表”一行数据代表“某用户在某时间支付了某商品多少钱”。DWS层建一张“交易域支付汇总表”按“支付日期 用户 商品 店铺 省份 支付渠道”做一次汇总得出每个组合的支付订单数、支付金额、支付商品件数等度量。这样业务方想看“某省某店铺某商品的日销售情况”直接查这张汇总表即可查询效率飙升。明细汇总是DWS层的基础也是使用频率最高的表类型它的设计要点在于维度的选取。维度选多细粒度就有多细汇总表的行数就有多大查询性能就受影响。我一般遵循一个原则支持报表和日常分析的最小必要维度。比如支付汇总表业务方常用的维度是时间、用户、商品、店铺、地区、渠道那我这六个维度都要有有些维度比如“支付终端型号”业务方几乎不用那就不放减少数据量。当然你不可能一开始就把所有维度都想全所以汇总表设计时要预留扩展字段的思路而不是严格固定死。3.2 什么是派生汇总型DWS表派生汇总型DWS表解决的是“周期型、累积型、复合型”指标的汇总问题。举个常见的例子用户留存分析。你很难用一张普通的按日汇总表算出“7月1日新增用户在第30天的留存率”因为“第30天留存”这个指标的观察窗口是横跨30天的必须基于“用户维度的完整生命周期”来做计算。这种表我就归到派生汇总型。再比如“截止昨日累计消费金额”这是一个累积型指标每天跑批时都需要把历史所有数据累加起来这种逻辑放在明细汇总型表里不好做也做不了因为它是“有状态”的必须单独设计一张“用户累积汇总表”每天更新记录截止到昨天的累计消费金额、累计消费次数、累计商品件数、首次消费时间、最近消费时间等。用户维度的很多分析比如RFM模型、用户分层都依赖这类表。派生汇总型表的建设逻辑是“实体为中心生命周期为线索”。这里的实体可以是用户、商品、店铺等每张表描述这个实体从“出生”到“现在”的全生命周期统计。这类表的数据量通常不会很大比如用户数可能就几千万但它的查询价值极高是精细化运营的核心数据底座。3.3 两种模型的适用场景和取舍我这里用一张表格帮大家梳理适用场景方便做技术选型的时候直接对号入座| 类型 | 适用指标 | 示例 | 更新频率 | 数据量 | | 明细汇总型 | 周期性、可累加指标 | 当日支付金额、当日新增用户数 | 每天全量或增量 | 较大 | | 派生汇总型 | 累积型、生命周期型指标 | 累计消费金额、用户30日留存 | 每天更新需回溯历史 | 较小 |选型上我个人的经验是如果指标只依赖“今天”的数据用明细汇总型如果指标需要结合“过去每一天”的数据用派生汇总型。两者不是互斥关系而是互补关系。比如用户留存分析既需要用户明细汇总表知道每天新增了谁又需要用户活跃汇总表知道这些用户之后哪天来过然后才能算留存。实际项目中我也遇到过把两种模型混着用的场景。比如做商品复购分析我们建了一张“商品维度的订单汇总表”这是明细汇总型但它里面同时包含“首次购买时间”和“最近购买时间”这两个派生字段用来快速识别新老客。这种做法在工程实现上没问题但要注意“派生字段的计算逻辑”要保持稳定否则出问题的时候排查成本和返工成本都很大。我更推荐的做法是核心的派生逻辑都收敛到派生汇总型表中明细汇总型表保持“轻量、干净、稳定”。3.4 宽表不是“越宽越好”行业内经常有人把DWS和“宽表”画等号好像DWS层就是拼命把维度、度量往一张表里堆。我要泼个冷水无脑加宽表后患无穷。一张表里有几百个字段听着很全能实际上用起来就是灾难谁也不知道每个字段怎么算的、更新频率是多少、哪个团队在用最后变成谁都不敢动的“定时炸弹”。我自己曾经接手过一个项目里面有张“全维大宽表”两百多个字段涵盖了订单、库存、用户、流量几乎所有信息。刚开始大家都觉得好使什么需求都能从这张表里出后来业务变化要改其中一个字段的计算逻辑结果改完以后下游几十张报表、十几个算法模型全部受影响光是回归测试就花了将近两周那个月我们团队几乎都在救火。宽表正确的打开方式是“高内聚、有限宽”。在同一个业务过程内把相关性高、使用频率高的维度和度量放一起比如“支付汇总表”可以宽因为它聚焦支付这一个业务过程。但不要把“支付汇总”和“物流签收汇总”硬塞到一张表里它们虽然都属于交易域但业务过程不同放在一起不仅数据量暴增而且任何一方的修改都会波及另一方。DWS层表设计要追求的是“单表语义清晰、可独立维护”而不是“一表打天下”。说到分区设计我也提一嘴。DWS层汇总表几乎都是分区表最常用的分区策略是按天分区因为调度也是按天跑批。如果业务有小时级分析的需求可以按小时分区但小时分区的表数据量会更大管理也更复杂我建议只在需求非常明确的场景使用。长时间跨度数据比如3年以上可以做归档分区或冷热分离降低存储成本同时保证热数据的查询性能。4. 指标体系落地口径统一是第一位的DWS层承载着整个数仓最核心的指标计算逻辑所以指标口径的统一是我们这个层面必须守住的底线。平时我们总说“指标治理”“指标规范”听上去像是偏管理的事情但实际上它在DWS层建设里面是最实打实的技术活。我在没有建立规范之前光是一个“销售额”就有好几种算法有人用订单金额有人用实付金额有人包含运费有人不含运费。业务方为了对上一个数来回扯皮不知道花了多少时间。这里想分享一个实际做法在做DWS层的表之前先做指标体系梳理。每张DWS表涉及哪些指标每个指标的业务口径是什么计算公式是什么统一的命名是什么这些要先讨论清楚写进文档然后才进入建表开发环节。业务口径不清晰DWS层建得再漂亮也是空中楼阁。4.1 一次指标口径梳理的实际过程我们在做交易域DWS层之前把所有涉及订单的指标全部拉出来和市场、运营、财务三个核心业务方开了两轮会。会上一个一个指标过比如“销售额”这个话题光是定义就讨论了将近一个小时。财务的口径是“按支付成功且未退款金额计算”运营的口径是“按下单金额计算”市场想看的是“含优惠券抵扣前的原始金额”三方需求都不一样。最终我的处理方式不是强行统一成一个“标准销售额”因为各方的诉求确实是合理的强行统一只会逼着业务方绕过你另建表。正确的做法是把指标拆成“原子指标”和“派生指标”来管理。“订单金额”“优惠金额”“退款金额”这类是原子指标直接对应业务过程本身“销售额”“净销售额”“实付金额”则是派生指标是在原子指标的基础上按不同口径组合出来的。|-|-| | 指标类型 | 指标名称 | 计算逻辑 | | 原子指标 | 订单金额 | sum订单商品金额 | | 原子指标 | 优惠金额 | sum优惠券分摊金额 | | 派生指标 | 销售额 | 订单金额 - 优惠金额 | | 派生指标 | 净销售额 | 订单金额 - 优惠金额 - 退款金额 |在DWS层我通常的做法是把原子指标都存储下来派生指标的计算留在ADS层去完成。这样做的好处是DWS层具备最大的灵活性上层想要什么口径用原子指标都能组合出来不需要回到ODS重新大量扫描数据。如果DWS层直接存派生指标那么每出一个新口径就要改造DWS表这会让底层表结构变得极不稳定。4.2 指标命名规范和元数据管理口径梳理清楚之后要落到纸面上形成规范的命名体系。我见过很多团队在建DWS表的时候字段命名随心所欲有人用order_amount有人用ord_amt有人用pay_money都是“订单金额”等表和表要去做关联计算的时候才发现两边字段是同一个东西气得想拍桌子。我们团队到后期形成一个不成文的规定所有DWS表字段名必须遵循“业务域_指标含义_统计周期”的规则比如“pay_amt_day”、“ord_cnt_day”、“ref_amt_mtd”。“day”结尾代表按日汇总“mtd”结尾代表月累计“itd”代表历史累计。这样一看字段名就知道这个字段是什么指标、什么统计周期极大降低了沟通成本。元数据方面每张表都要有说明文档包含业务口径、技术口径、更新频率、责任人并挂到元数据管理平台上。还有个容易被忽视的细节是指标的口径版本管理。业务口径不是一成不变的比如公司改了优惠策略原来算销售额不扣优惠券现在要扣那么对应的指标逻辑就得变。遇到这种情况要留好版本记录明确“从哪天开始新口径生效旧口径数据保留多久”我见过最惨痛的例子是有团队在旧数据上直接更新了口径导致历史数据和财报对不上最终只能推倒重算。这种事故建立好版本管理机制是完全可以避免的。4.3 计算方式差异举两个典型例子一个是去重指标的计算。比如“日活跃用户数DAU”看起来简单无非就是“当天活跃用户去重计数”但严格来说却分好几种口径按用户ID去重、按设备ID去重、按手机号去重三者的数量都不一样选择哪个口径要看业务诉求。在DWS层设计时最好的做法是明确定义一种主口径通常按用户ID同时保留其他口径的统计结果作为冗余字段存在同一张汇总表里。这样后续分析如果发现主口径有问题还能从冗余字段找到兜底数据。另一个是比例类指标。比如“支付转化率”分子是支付用户数分母是曝光用户数分子和分母来自不同的主题域曝光来自流量域支付来自交易域。如果两个主题域的计算时间不一致比如流量域10点跑完、交易域10点半跑完那么当天任何10点到10点半中间查询转化率的用户拿到的都是一个“中间态”数据分子分母都是“缺的”。为了避免这个问题我们在DWS层设计调度时会给转化率指标专门设置一个“数据就绪”检测两个域都跑完才会把结果推给下游宁可晚出数5分钟也不出一个脏数。总结下来DWS层的指标体系落地核心就三件事拆分原子与派生、统一命名和口径、明确更新逻辑。这三件事做扎实后面的报表开发和数据分析都会非常顺畅。5. 调度与产出从“能出数”到“稳出数”DWS层建表只是开始真正的挑战在于调度和产出稳定性。我自己经历过业务方早上9点上班发现昨天的核心报表数据还是空的然后一通电话打到数仓这边来“问罪”的场景。次数多了以后就会明白DWS层建设不能只盯着表怎么设计调度设计、性能调优和数据质量校验才是保证DWS层稳定输出的护城河。5.1 调度依赖和基线时间设计DWS层的调度依赖关系核心原则是“从上游到下游逐层依赖层层递进”。ODS跑完才能跑DWDDWD跑完才能跑DWSDWS跑完才能跑ADS。这个依赖关系在设计DWS任务时特别关键因为DWS往往同时依赖多个DWD表比如“交易域支付汇总表”至少依赖“订单支付明细表”和“订单商品明细表”两张DWD表都必须成功跑完DWS任务才能启动。在调度平台上我习惯给每个DWS任务设置一个“截至时间”和一个“预警时间”。比如交易域核心汇总表要求每天早上7点前产出那么预警时间设在6点半如果6点半还没跑完调度系统自动给责任人发告警。这样还不至于影响业务方使用。千万别等到业务方发现了你才知道数据没出那个场面非常被动。基线时间的设计要预留“安全缓冲”不要卡死。我们有一个血的教训曾经把核心表的产出截止时间设成跟下游报表发布时间完全一致结果某天上游数据延迟了20分钟整条链路全部雪崩下游报表全部空跑业务方当天看到的是“ー”一片空白。后来我们强制要求DWS层内部每层任务之间预留至少30分钟缓冲即使上游波动下游也不会直接挂掉。宁可让数据早产出、在那儿闲着也不能让下游等着用的时候找不到数。5.2 任务跑批时长优化从3小时到30分钟DWS层最容易出现的性能瓶颈就是每日跑批时间过长。高峰期项目交易域汇总表跑批曾经需要将近3个小时严重拖累下游所有任务多次优化后压缩到30分钟以内这里分享几个实打实的优化方向。第一个是减少扫描量。用分区裁剪代替全表扫描每次运行前先确认SQL的where条件是否带上了分区字段别一张几亿行的表从头扫到尾。有些团队的SQL跑得慢不是计算量大就是扫描量太大这一个优化往往就能带来几倍的性能提升。第二个是合理设置并行度。很多大数据引擎跑批慢是真没把资源用起来一个任务默认并行度32跑几亿行数据肯定慢适当提升并行度比如128只要资源池够性能提升非常明显。第三个是用小表做维度关联。在DWS层汇总时如果需要关联维表优先使用广播小表避免大表和大表之间进行Shuffle这是最容易踩的坑。还有一点很重要如果DWS层有多个业务过程要汇总优先考虑“先合并再聚合”而不是“多次扫描源表”。比如要同时统计“支付用户数”“支付订单数”“支付金额”三个指标最好一个SQL扫一遍一次性计算出来而不是拆成三个SQL扫三遍。这个习惯从一开始就要养成否则表数量一多集群资源很快就不够用了。5.3 数据质量校验不等业务方来质疑数据质量是DWS层建设的生命线数据错了比数据没了更可怕。数据错了业务方会拿着错误的数据做决策做出误判之后数仓团队的信用就崩了。所以我要求DWS层每张核心表都必须配置数据质量校验任务挂在调度里每天自动跑。校验规则我常用的有几种。一是完整性校验比如“当天支付汇总表的记录数必须等于DWD支付明细表按照相同维度去重后的记录数”如果不等说明DWS的group by逻辑可能有问题或者上游数据缺失。二是空值校验比如“用户ID为空的行数必须为0”如果出现空值大概率是DWD的清洗环节有bug要第一时间定位。三是波动率校验比如“今天的GMV跟过去7天均值比波动不能超过50%”一旦超过就要检查是业务活动大促导致的正常波动还是数据异常。我印象很深的一次就是靠波动率校验发现了一个严重的数据倾斜问题。某天凌晨两点质量校验任务报警“华东地区订单量环比飙升300%”我半夜起来查发现是一名开发在DWD层做维度退化的时候把“店铺ID”字段跟“订单ID”搞混了几百个店铺的订单全部挂到了一个店铺下面。如果没有校验任务第二天早上业务方看到的就是荒谬至极的数据然后再花一整天去排查。从那以后我就把“数据质量校验”当成DWS层建设的标配环节不是可有可无的加分项而是必须具备的基础设施。6. 常见问题与排查技巧实录DWS层建设过程中遇到的问题五花八门我挑了四个最有代表性的列出来每一个都是真金白银换来的教训。如果你正在建设DWS层建议把这几个场景都过一遍遇到类似问题的时候至少有个方向。6.1 汇总数据不一致问题最让人抓狂的问题莫过于两个报表看同一个指标数字却对不上。比如报表A显示昨日支付金额100万报表B显示昨日支付金额98万差异从哪来正常情况下字段含义、计算逻辑都已经统一了那么剩下的最大嫌疑就是汇总粒度不一致。A报表用的DWS表是“支付日期用户支付方式”粒度B报表用的DWS表是“支付日期用户商品店铺”粒度商品维度下钻之后用户在不同商品上支付了多笔重复计数导致金额被放大或缩小。排查这种问题我的习惯是先让两张报表都“裸查”DWD层原始明细确认哪个是对的然后再逐层往上看看是哪一层聚合逻辑出现了偏差。如果DWD一致、DWS不一致那就是DWS汇总逻辑的问题如果DWD都不一致那问题出在上游ODS清洗或数据同步。只要“从下往上逐层核对”的排查习惯建立起来这类问题通常半小时内能定位。6.2 同步延迟导致DWS空数据上游业务系统凌晨有大促活动数据库压力很大同步任务跑到早上6点才完成而DWS的调度是5点就启动了等DWS开始跑的时候发现ODS的当天数据还没到然后就直接跑了一个“只有历史数据、没有当天数据”的汇总结果。这种问题的高发期是大促期间和业务高峰期。解决思路是设置任务间的“依赖等待”机制。调度上不能只看“上游任务是否跑完”还要校验“上游分区的数据是否完整”比如判断ODS层的分区记录数是否大于0、跟历史均值比是不是在正常波动范围内。如果数据没就绪DWS任务进入等待状态直到就绪才触发。这种机制刚开始搭建的时候有点繁琐但建好之后能避免非常多脏数据事故。6.3 长周期累积表的数据膨胀按天分区的汇总表数据量是线性增长的但用户维度的累积表比如“用户消费累计表”每天都要更新数据如果不做处理表数据量会随着时间无休止地膨胀。有段时间我们是全量刷新一开始没什么感觉等到用户量上千万、跑批时间超过一个小时才意识到问题的严重性。后来改成了增量更新 拉链表机制。每天只更新变更的用户数据而不是全表覆盖。对于不发生变化的用户记录保留历史不变对于有新增或变更的用户生成新的记录并标注有效期。这样既保证了数据准确性又控制住了存储和计算成本。这也是为什么我在前面强调派生汇总型表的设计一定要考虑“状态变化”的场景不能简单粗暴地照搬明细汇总型的全量刷新的思路。6.4 维度太多导致表泛滥还有一个非常普遍的问题为了满足各种分析需求DWS层的汇总表越建越多每个维度组合都建一张表最后DWS层的表数量比明细层还多MT维护成本极高。比如今天业务方要看“按用户维度的支付汇总”建了一张表明天要看“按商品维度的支付汇总”又建了一张表后天要看“按省份维度的支付汇总”再建一张这样下去永远建不完。这个问题我现在的解法是“先建统一粒度大宽表 动态裁剪”。还是拿支付举例先建一张“按用户商品店铺省份支付日期”粒度的支付汇总宽表这张表的粒度是最细的其他所有维度组合的查询都可以在这张最细粒度的表上通过SQL二次聚合完成。如果某个维度组合的查询频率特别高再考虑单独物化出来如果只是偶尔查一次完全不建表、直接上卷查询即可。这个方法有效地将DWS层的表数量控制在了一个可管理的范围内也兼顾了查询性能。一点个人体会做DWS层建设这几年我最大的体会是这一层表面上是技术问题实质上是一半技术、一半管理。技术上的建表、调度、调优都有明确的规则可循花时间总能搞定难的是口径的统一、主题域的划分、规范的形成这些需要跟业务方反复沟通需要团队长期共识没有任何捷径。DWS层就像是一个城市的交通枢纽设计得好整个城市的通行效率就高设计得潦草每个路口都会成为堵点每天都会有人迟到。如果你刚开始做DWS层我建议不要一上来就追求大而全先挑一个核心主题域比如交易域把链路从ODS到ADS完整打通验证方案可行再复制到其他主题域。这套思路真的比憋大招稳得多。最后再分享一个小技巧DWS层每张新表上线前都拿着“它到底替代了之前的哪些重复计算、服务了哪些下游需求”这个问题审视一遍答不上来的表就推迟上线。这样你的DWS层才会越建越精、越用越顺。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门