ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

数据仓库核心知识:ETL分层、维度建模与拉链表实践

数据仓库核心知识:ETL分层、维度建模与拉链表实践

简介:《数据仓库工程师面试题》是一份面向数据仓库求职者与初、中级数仓开发者的docx文档,聚焦面试常见概念与工程实践梳理。文件共1个,为docx格式,压缩包约31KB,轻量便于查阅。已有1712人学习下载,具备一定参考热度。内容围绕数据仓库定义与主题性、集成性、稳定性、时变性展开,并串联ETL抽取转换加载、日志分类与告警发送、Hive等常见数仓选型;进一步覆盖STG、ODS、DW、Presentation四层模型,以及各层作用、开发步骤、CDC策略、mapping与物理模型设计。还涉及数据清洗、规范化、去重合并、维度表和事实表提交、代理键与缓慢变化维等要点,适合面试前系统复盘、查漏补缺,也可作为日常开发中的知识速查提纲。

1. 数据仓库是什么:先把它想成超市的后仓

你去超市买东西,看到的是货架上分好类、贴好价签的商品;但超市真正的功夫在后仓——各个供应商送来的货整箱堆着,包装不一样、计量单位不一样,后仓的人要拆箱、验货、贴标、按品类上架,货架才能保持整齐。数据仓库在企业里就是那个后仓:它不直接服务某一笔业务,而是把散落在多个业务系统里的数据收过来,清理、统一、按主题摆放好,供人分析和决策,英文叫 Data Warehouse,简称 DW。搞懂它,你就明白为什么公司明明有一套跑得好好的业务数据库,还要单独养一套又贵又慢的系统——这背后的取舍,是数据仓库知识里最值得先弄清楚的一块。

2. 为什么不能直接查业务库:四个特点撑起的另一套账本

2.1 收银台和财务室,不能用同一张桌子

业务数据库干的是收银台的活:每秒钟接一笔下单、一次支付、一条库存变更,要求是快、准、不互相锁死,事务一提交立刻生效。数据仓库干的是财务室的活:要看过去三年每个季度、每个区域、每个品类的走势,一次扫几千万行甚至上亿行,还得把历史状态保留下来。

这两种活对同一份数据的要求几乎相反。收银台希望表越窄越好、并发越高越好、每次只碰一行;财务室希望一列一列地扫、能容忍响应慢几秒、能翻出半年前那条记录当时长什么样。把两种需求压在一张表上,结果就是两边都难受:白天有人跑报表,业务库的响应时间肉眼可见地涨;赶上大促,报表任务被业务写入挤得排队。这不是调参能解决的问题,是结构性冲突。

还有一层更隐蔽的原因:口径。同一家公司的销售系统、客服系统、财务系统里,客户可能有三套编号,性别字段一边存 0/1、一边存 man/woman,订单状态一边叫"已支付"、一边叫"PAID"。做分析的人如果每次都要自己去猜、去对、去拼,那么十个人会算出十个不同的月度营收。数据仓库存在的第一个理由,就是把这些脏活集中干一次,让后面所有人拿到的是同一份对齐过的数。

所以数据仓库不是"业务库的备份",它是另一套账本,为分析而生,为口径统一而生。

2.2 主题性与集成性:先把"说的是同一件事"对齐

主题性说的是组织方式。传统业务库按项目或按系统切分,销售库管订单、客服库管工单,各管一摊。数据仓库不这么切,它按使用者关心的主题切:客户、产品、订单、渠道、财务。所有进来的数据,最后都要围绕这些主题重新摆放。

打个比方,业务库像五个各自记账的柜子,数据仓库像按"人、货、钱"重新分类的一个大档案室。一个客户在销售系统里是会员号、在客服系统里是手机号、在财务系统里是开票抬头,到了数据仓库,这些线索被合成同一个"客户"实体下的不同属性。

集成性是主题性能成立的前提。数据来自多个源,格式、编码、粒度、更新频率都不一样,必须经过抽取、清洗、转换这一整套动作才能合成一个整体——这套动作就是 ETL。举个最小的例子:三个源系统的性别字段分别是0/1、man/woman、M/F,数据仓库里统一映射成m/f,下游任何一张报表都不用再写一遍 case when。

主题性和集成性合起来,解决的是"同一件事在不同系统里有不同说法"这个根子上的问题。没有这两条,数据仓库就只是个更大的硬盘。

2.3 稳定性与时变性:老账不动,新账追加

稳定性指的是数据仓库里保存的是一系列历史快照,不允许被随意修改。用户能做的只有查询和分析,不能上去 update 一行把上个月的营收改掉。

很多人第一次听到这条会疑惑:数据不是天天在变吗,怎么能说不许改?这里的关键是"改"的含义。业务库里的改,是覆盖——客户改了手机号,旧号码就没了。数据仓库里的改,是追加——新的一天进来一份新快照,旧快照原样躺着,你既能看到客户今天的号码,也能看到三个月前他留的是哪个号。

时变性说的是它会定期接收新的集成数据,反映最新的变化。这两条听着打架,其实分工明确:稳定性保的是"历史不能被抹掉",时变性保的是"新数据能进来"。一个管纵轴,一个管横轴。

这个特性直接决定了数据仓库能做很多业务库做不了的事。比如某产品调价,你想知道调价前后各一个月的销量差异;比如风控要复盘三个月前某笔订单当时的风控标签是什么。业务库只会告诉你"现在是什么",数据仓库能告诉你"当时是什么"。

2.4 输入是杂乱的源,输出是能拍板的数

数据仓库的一头连着各种各样的数据源:关系型业务库、文件形式的导出数据、日志、手工维护的表格,甚至非结构化的文本。另一头连着数据分析、数据挖掘和数据报表。

这个"进杂出整"的过程,决定了它必须有一套自己的工程方法。源头越杂,抽取环节要调研的东西就越多:数据从几个业务系统来、各跑在什么数据库上、有没有手工数据、手工数据量多大、有没有非结构化数据。这些不问清楚,抽取设计就是拍脑袋,后面全是返工。

输出端则决定了它的评价标准不是"存得多",而是"能不能支撑决策"。一张报表能不能在一个合理时间内跑出来、同一个指标在两张报表上是不是同一个数、业务方追问"这个数怎么来的"时能不能一路追溯到源头的某一行——这些才是数据仓库的成败线。

理解了输入输出的两端,再看后面那些 ETL、分层、维度建模的名词,就不会觉得是一堆孤立的规矩,而是一整套为了让"杂"变"整"而长出来的方法。

3. ETL 与四层模型:一条数据要过几道"洗"

3.1 ETL 三个字母,各自对应一个动作

ETL 是 Extract、Transform、Load 的缩写,翻译过来就是抽取、转换、加载。数据仓库要做数据集成,靠的就是这三步。

Extract 是抽取,把数据从源系统读出来。听起来最简单,实际最费功夫,因为源系统的脾气各不相同:同一种数据库之间可以直连写 select,不同类型的数据库之间要走通用连接方式,连不上的就导出成文本或表格文件再导入,再不行只能走程序接口。文件类型的数据源还得先教会业务人员按规范导出。

Transform 是转换,把原始数据加工成期望的格式与维度。在数据仓库场景下,这一步还包括数据清洗,把噪音数据、不完整数据、错误数据挑出去。常见的三类脏数据是:该有的信息缺失(供应商名称空着、客户区域没填)、格式错误(数值被输成全角字符、字段前后带不可见空格)、重复记录(同一个客户在两个系统里各存一份)。

Load 是加载,把处理完的数据写进目标,比如数据仓库的某一层。加载不是简单 insert,里面藏着增量判断、去重、关链开链这些动作,后面讲拉链表时会看到。

三步里最容易被低估的是转换。抽取和加载更多是工程问题,转换则混合了业务规则——什么算"同一个客户"、什么算"有效订单",这些判断一旦写错,后面所有报表都是错的,而且错得很安静。

3.2 STG、ODS、DW、DM:四层各守一道门

传统数据仓库一般分四层,每一层解决一个特定的问题。分层不是为了好看,是为了让出问题时能快速定位、让需求变化时不至于推倒重来。

层模型风格数据范围主要动作解决的问题
STG与源系统一致增量或全量抽取不做转换,只加审计列减轻源系统压力,支持重跑
ODS与源系统一致全量历史标逻辑删除、标增量时间戳、加审计列减少需求变化带来的冲突
DW维度模型增量清洗、规范化、一致性处理便于数据问题跟踪
DM聚合或宽表按业务需求聚合事实表、缩小维度表直接支撑报表与分析

STG 层是落地层。它面向批处理,按 CDC 策略把各源系统的数据先搬进来,不做任何转换,只额外加几个审计列:源系统名称、源表名称、加载时间、加载方式。作用是降低开发和维护成本——数据先原样落一份,后面转换逻辑改了可以重跑,不用再去骚扰源系统。如果是基于日志的实时同步,可以跳过 STG 直接进 ODS。

ODS 层是存档层。它保留源系统的全量历史数据,和 STG 最大的区别是多了两样东西:逻辑删除标记和增量时间戳。为什么需要逻辑删除标记?因为很多源系统会做物理删除,甚至有人在后台手工删数据,删完之后你在源库里连痕迹都找不到。ODS 靠比对发现"这条以前有、现在没了",给它打上删除标记,历史才不会凭空缺一块。

DW 层是工作区。清洗、规范化、一致性维度与事实都在这里完成,建立反规范化的维度模型。所谓规范化,就是把各业务系统在命名和取值上的差异统一掉,形成企业标准版本的数据:内容、格式、命名、计算规则都收敛到唯一版本;再做去重、合并、拆分,把多个源系统维护的同一个对象合成一条。

DM 层是对外的展台。按业务需求把 DW 层的数据聚合成宽表或聚合表,比如按月的销售汇总、按区域的客户数。聚合表有三种常见做法:增量加载聚合表、聚合导航(用户点报表时按请求自动生成聚合数据)、物化视图定时刷新。因为聚合表的粒度和基础事实表不一样,还得配上粒度相同的缩小版维度表。

这四层连起来看,是一条从"原样搬运"到"清洗对齐"再到"按需聚合"的流水线。每一层都可以单独重跑,每一层出问题范围都有限,这就是分层的价值。

3.3 动手顺序:先定 CDC,再画 mapping,最后落物理模型

知道了有哪几层,还得知道先干哪一步。一个可复现的顺序大概是这样。

第一步,确定 CDC 策略。CDC 指变更数据捕获,说白了就是"怎么知道源系统哪些数据是新的、哪些改过"。源系统有时间戳就用时间戳,有日志就吃日志,什么都没有就只能全量比对。这一步选错,后面要么天天全量扫库被 DBA 追着骂,要么漏数据漏得莫名其妙。

第二步,设计 mapping 文档。把源表的字段和目标表的字段一一对应写清楚,包括转换规则、默认值、过滤条件。这份文档是开发、测试、验收三方唯一的共同语言,跳过它直接写代码,最后一定会为"这个字段到底该取哪个"扯皮。

第三步,设计物理模型。以 STG 层为例,物理模型一般包含源系统的所有字段加审计列,可以去掉主键、索引、默认值这些约束,因为这一层只负责搬运。如果源表和目标表的数据库类型不同,字段长度最好做扩充,目标表的数据类型只挑几种常用的、长度只挑几个固定值,免得每天为类型转换踩坑。

-- STG 层建表:只搬运,不转换,因此不设主键和索引 CREATE TABLE stg_order ( order_id VARCHAR(64), -- 源系统订单号,长度统一放宽到 64 customer_id VARCHAR(64), -- 源系统客户号 order_amount DECIMAL(18, 2), -- 订单金额,精度按目标库习惯固定 order_status VARCHAR(32), -- 订单状态,先原样存,不翻译 src_system VARCHAR(32), -- 审计列:数据来自哪个业务系统 src_table VARCHAR(64), -- 审计列:数据来自哪张源表 load_time TIMESTAMP, -- 审计列:本次加载时间 load_type VARCHAR(16) -- 审计列:全量还是增量 );

这段建表语句里有三处刻意为之。一是所有字符串长度都放宽并固定,避免源库换一次类型就得改一次表。二是没有任何主键、索引和默认值约束,因为 STG 只做落地,约束会拖慢批量写入。三是四个审计列,它们看起来可有可无,实际是排查问题的抓手——某条数据对不上时,先看src_system和load_time,能立刻判断是哪个源、哪一批出的问题。

第四步,抽取数据。STG 层面向异构数据源,最好用支持多种数据源的 ETL 工具来做,别自己写一堆脚本。

第五步,加载数据。STG 层一般只保留 7 天到一个月的数据,它的定位是缓冲,不是档案室。

3.4 日志与告警:出问题时唯一的黑匣子

ETL 任务动辄几百个,凌晨跑批,白天没人看着。第二天早上发现报表空了,如果没有日志,排查就是从零开始。

ETL 日志通常分三类。执行过程日志记的是每一步的流水账:这一步几点开始、几点结束、影响多少行。错误日志记的是出问题时的现场:什么时间、哪个模块、什么错误信息。总体日志最粗,只记整批任务的开始时间、结束时间和成功与否。如果用的是成熟的 ETL 工具,工具本身还会自动产生一部分日志,这部分同样要收进来一起看。

光有日志不够,还得有告警。ETL 出错时,除了写错误日志,要主动通知系统管理员,最常见的方式是发邮件,把出错信息附上,让人一眼能判断严重程度。这一步经常被省略,理由通常是"反正第二天会看"。然后就会遇到那种情况:某个上游表结构调整了,任务连续三天空跑,没人发现,直到业务方拿着空报表找上门。

日志和告警加起来,构成了 ETL 的黑匣子。它的价值不在于平时,而在于翻车那一刻——有它,十分钟定位;没它,通宵猜谜。

4. 事实表与维度表:维度建模的两个基本零件

4.1 事实表记的是"发生了什么"

事实表是数据仓库里最占空间、也最直接回答业务问题的表。它记录的是业务过程中发生的一件事:一笔销售、一次支付、一条库存变动。表里主要放数字和标志位,用来做求和、计数这类统计,比如收益、数量、支出。

事实表有个铁律:一张事实表只能有一个粒度。粒度指的是每一行代表什么,是"一个订单行"还是"一天一汇总"。把不同粒度的事实塞进同一张表,等于把苹果和苹果箱子放一起称重,任何汇总都会重复计算。

按粒度和时间特征,事实表大致分四类:

类型记的是什么典型例子ETL 中的生成方式
事务粒度事实表特定时间、空间点上的一次瞬间测量销售单、支付流水以原子粒度直接迁移,可直接求和计数
周期快照事实表一个时间段或规律性重复的状态月末账户余额、月度库存按固定时间间隔生成累计数据
累积快照事实表有明确开始和结束的完整过程合同履行、工单流转随着流程推进逐步补全同一行
无事实事实表事件发生了,但没有可测量的数值员工考勤打卡、促销活动覆盖只记录事件与维度的关联

周期快照的要点是:表里每一行必须量测的是同一个时间段内的活动,粒度对齐了才好比较。累积快照不适合长期连续跟踪,它描述的是一段有始有终的流程,随着步骤推进不断更新同一行。无事实事实表最容易被忽略,它没有度量值,存在的意义是回答"有没有发生过"这类问题。

4.2 维度表是分析的窗口

维度表是用户观察数据的角度。它包含事实表里那些描述性信息,也包含用来汇总的层次结构。想知道"哪个区域卖得最好",区域就是维度;想知道"哪一类产品毛利高",品类就是维度。

维度表通常比事实表小得多,但字段宽,且直接决定分析的体验。维度类型大致有这几种:

缓慢变化维,指那些会变但变得不快的属性,比如客户地址、员工职级。这是最常见的一类,处理方式下面单独说。

快速变化维,指变化频率很高的维度,比如产品价格、搜索关键词。在一个分析用户搜索行为的项目里,关键词作为维度,数据量会迅速膨胀;精度到秒的时间维度更是每秒新增一个值。处理方法要按规模分:字段少、数据量小的,用缓慢变化维的第二型(新增一行、旧行置过期)就够;字段多、数据量大的,用第三型(只保留上一个值和当前值)避免行数爆炸;最糟的是字段又多、数据量又大、还有一部分字段频繁变,这时要把稳定字段和频繁变化字段拆开,让频繁变化的部分独立成新维度表。

大维和迷你维是一对。客户、产品这类维度动辄上百万甚至上千万行,每条记录上百个字段,直接查会很慢。常见的优化是把大维度里最常查的少数字段单独提出来,形成一张字段少的迷你维,查询时先走迷你维,效率明显提升。

退化维指的是那些留在事实表里、不单独建维度表的维度,通常是订单号这类业务主键。它没有描述性属性,单独建表纯属浪费。

还有一个容易被忽略的细节:维度表的每个字段都要设默认值,不能为空。首次加载时要有第一条代理键为-1的默认记录,专门用来兜底——当事实表按业务主键找不到对应维度时,关联到这条默认记录,而不是让整行数据消失。这个设计看起来有点丑,但它能保证事实表的行数永远是完整的,不会因为一个维度缺失就少算一笔钱。

4.3 缓慢变化维:一个人的地址变了怎么记

缓慢变化维是面试里出现频率极高的一道题,因为它没有唯一正确答案,只有取舍。

第一型是直接覆盖:新值代替旧值。优点是表小、简单;缺点是历史全丢,你再也查不到"这个客户去年在哪个城市"。

第二型是增加新行:把当前这一行的状态置为失效,打上结束时间戳;同时新增一行,状态置为有效,开始时间戳设为上一行的结束时间加一。这是保留了完整历史的方式,代价是行数会增长。

第三型是增加新列:给表加一列存新值,原来的列保留旧值。它只能保留"上一个值",再往前就没了,适合变化极少且只关心前后对比的场景。

选哪种,取决于业务问的问题。如果业务只关心"现在这个客户属于哪个区域",第一型就够;如果业务会问"这笔订单发生时客户属于哪个区域",那必须用第二型,因为区域调整会影响归属,历史归属必须能还原。

4.4 拉链表:两个日期字段换几十 TB 空间

拉链表是第二型缓慢变化维在工程上的落地形态,也是数据仓库里最实用的一个技巧。

它要解决的问题很具体:一张用户表十亿条记录、五十个字段,即使压缩,单表存储也超过一百 GB,再算上分布式文件系统的多副本,占用更大;而这张表里每天真正发生变化的可能只有两百万行左右,变化比例很小;同时业务又需要查看某个历史时间点的状态。如果每天存一份全量快照,绝大部分空间都在存没变过的数据。

拉链表的做法是给表加两个日期字段:start_date和end_date。一行数据从start_date开始有效,到end_date失效;当前仍然有效的行,end_date给一个极大值,比如9999-12-31。

实现分两步。先在 ODS 层建一张ods_order_update表,只存当天变化的数据,包括新增和更新。然后把这张增量表和拉链表做交集,对命中的历史记录做封链操作;再把增量数据插入拉链表,start_date设为当天,end_date设为极大值。

-- 第一步:关旧链。只处理那些还开着链、且今天确实发生了变化的历史行 UPDATE dw_order_his h SET end_date = CURRENT_DATE WHERE h.end_date = DATE '9999-12-31' AND EXISTS ( SELECT 1 FROM ods_order_update u WHERE u.order_id = h.order_id -- 按业务主键匹配 ); -- 第二步:开新链。当天变化的全部数据追加进历史表 INSERT INTO dw_order_his (order_id, customer_id, order_amount, start_date, end_date) SELECT order_id, customer_id, order_amount, CURRENT_DATE, -- 新链从今天开始生效 DATE '9999-12-31' -- 极大值表示仍然有效 FROM ods_order_update;

两个参数值得注意。end_date这里直接取CURRENT_DATE,有些团队会取CURRENT_DATE - 1,目的是让新旧两条链在日期上不重叠,避免按日期区间查询时同一行被算两次,两种写法都能跑,关键是在整个项目里统一。另一个是9999-12-31这个极大值,它是"仍然有效"的约定标记,所有下游查询都要按这个约定写条件。

查询某个历史时间点也很直接:

-- 查 2024-06-30 这天仍然有效的订单状态 SELECT order_id, customer_id, order_amount FROM dw_order_his WHERE start_date <= DATE '2024-06-30' AND end_date > DATE '2024-06-30';

拉链表也会遇到性能问题。存了五年数据之后表会很大,查询自然变慢。常见的两个思路:一是在start_date和end_date上建索引,让区间条件能走索引;二是保留一份全量拉链表,同时对外暴露一张只提供近三个月数据的视图,绝大多数查询走小表,只有追溯历史时才碰大表。

5. 最容易混的五个概念:别把拉链表当成全量快照

5.1 数据仓库、业务数据库、数据湖

易混点:三者都存数据,名字里都带"数据",初学时常被当成同一个东西的不同叫法。

为什么混:它们确实是同一家公司里的三套存储,物理上可能就在同一个机房,日常对话里也经常被简称为"库""仓""湖"。

怎么区分:看它主要服务谁、存什么形态。业务数据库服务的是在线交易,存的是一行行结构化、随时会被覆盖的当前状态,要求高并发低延迟。数据仓库服务的是分析决策,存的是围绕主题组织、经过清洗整合、保留历史快照的结构化数据,允许慢一点但要求口径统一。数据湖更宽,它先原样存下各种形态的原始数据(结构化、半结构化、文本、日志),结构在读的时候再定义,适合还没想清楚要怎么用的数据。一个常被用到的比喻是:数据库是收银台账本,数据仓库是整理好的财务报表,数据湖是堆原料的仓库。顺序上通常是原始数据先进湖或 STG,再加工进仓。

5.2 星型模型与雪花模型

易混点:两者都是维度建模,都有一张事实表围着若干维度表,看图容易觉得只是连线方式不同。

为什么混:名字都来自图形——星型像一个星星,雪花模型像一片雪花,实际项目里两种往往混着用,边界不那么清晰。

怎么区分:看维度表是否直接连事实表。星型模型里,所有维度表都直接连到事实表,维度不再往外延伸,是一个非正规化的结构,因此存在一定数据冗余;好处是很多统计不需要做外部关联,效率通常更高。雪花模型里,部分维度表不直接连事实表,而是通过其他维度表连过去,维度被拆成了多层,减少了冗余,但查询时要多关联几张表。判断标准很简单:冗余可以接受,就用星型;维度层次很大且相对静态,需要严格控制冗余,才考虑雪花。

5.3 拉链表与全量快照表

易混点:两者都能查历史,都能回答"某天的状态是什么"。

为什么混:如果只存一天的数据,两者看起来一样;很多项目一开始用全量快照,后来存储扛不住才换成拉链表,迁移过程中两套逻辑并存,更容易糊。

怎么区分:看一天的变化量占比和存储成本。全量快照是每天一份完整拷贝,实现简单、查询直接,但空间随天数线性增长,变化率低的表会浪费大量空间。拉链表只存变化,一行数据用起止日期表示它有效的区间,空间节省非常明显,代价是查询要带区间条件,关链开链的逻辑也必须写对。经验判断是:日变化比例很低(比如十亿行里每天只变两百万行)、又要保留长期历史、还不想为存储买单的表,用拉链表;变化频繁、历史查询需求又弱的,全量快照反而省心。

5.4 缓慢变化维的三种类型

易混点:第一型、第二型、第三型,编号像难度等级,很多人记成"一二三越来越高级"。

为什么混:三种方式都能处理"属性变了"这件事,区别只在保留多少历史,而编号本身不表达这层含义。

怎么区分:按保留历史的能力记。第一型覆盖,只留最新值,历史为零。第二型加行,每一段历史都有一行,历史完整,代价是行数增加,这也是拉链表的基础。第三型加列,只留上一版,能对比"改之前和改之后",再往前没有。选择依据不是先进程度,而是业务会不会问"当时是什么"。会问,就必须第二型;只问现在,第一型最省;只做前后对比,第三型够了。

5.5 全量抽取与增量抽取

易混点:都叫抽取,都是把数据从源系统搬到仓库。

为什么混:很多表第一次加载必须全量,之后才转增量,同一张表两种方式都会用到,讨论时容易各说各的。

怎么区分:看每次搬多少、靠什么判断"新"。全量抽取每次都把源表整份搬过来,简单可靠但压力大,只适合小表或首次初始化。增量抽取只搬变化的部分,前提是能找到变化的标志——最常用的是业务系统记录的时间戳:每次抽取前先查目标表里已有的最大时间,再去源系统取大于这个时间的所有记录。麻烦在于很多业务系统没有时间戳,或者只有部分表有,这时就得靠日志、靠版本号,或者退回全量比对。选型时要先调研清楚源系统的数据状况,再决定 CDC 策略,这一步做错,后面所有优化都是在补窟窿。

6. 什么时候该建数据仓库,什么时候先别急

判断该不该建,先看三个信号。

第一个信号是"口径打架"。同一份月度营收,销售部算出来一个数,财务部算出来另一个数,开会先花半小时对数。这说明整合层缺失,靠人肉对账已经撑不住了。第二个信号是"业务库被报表拖垮"。白天跑一个分析查询,线上交易响应明显变慢,DBA 开始限制查询时间。第三个信号是"要回答当时是什么"。风控要复盘三个月前的订单标签,运营要看调价前后的销量对比,业务库只保留当前状态,根本答不上来。

反过来,三种情况可以先别急着上。数据量很小、源头只有一个系统、分析需求就是几张固定报表,这时候直接在主库上建只读副本、写几条 SQL 就够了,上一整套分层和调度,维护成本远大于收益。需求还在剧烈变化、连"客户到底怎么定义"都没吵清楚的阶段,先做数据调研和口径定义,比先建表更有价值。团队里没人能维护调度、日志和重跑机制的时候,建出来的仓库会在半年内变成没人敢碰的黑箱。

场景建议理由
多源系统、口径不一致建整合和标准化是核心价值
需要长期历史追溯建业务库不保留历史快照
报表明显拖慢线上业务建物理隔离分析负载
单源、数据量小、报表固定暂缓只读副本即可满足
口径未定、需求剧烈变动暂缓先做数据调研与口径定义
无人维护调度与日志暂缓缺乏运维能力会迅速腐化

有个踩坑经历我印象很深:早些年接手一个项目,源系统只有一套,数据量也不大,但当时觉得"规范一点总没错",硬是搭了四层模型加调度。结果需求一周改三次,每次都要从 STG 改到 DM,四个层全得动,改一次两天。后来把中间两层砍掉,只留落地层和汇总层,同样的问题半天就能改完。分层是有成本的,层数要和需求稳定性匹配,不是越多越专业。

从那以后我每次评估要不要建仓、要建几层,都会先强制走一遍三个问题:源头有几个、口径吵不吵、谁会来维护。三个都答得清楚,再动手。这份面试题整理里,四层模型的分工、缓慢变化维的三种处理、拉链表的关链开链、星型与雪花的选择,都按可复述的方式串成了一条线,比零散地背名词更容易在真被追问时站得住。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进