ARTICLE DETAIL

资讯详情

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

游戏数仓校招笔试复盘:从维度建模到SQL实战的完整指南

游戏数仓校招笔试复盘:从维度建模到SQL实战的完整指南 秋招季总有人跑来问我游戏公司的数据仓库开发工程师笔试到底考什么最近一个学弟把当年参加搜狐畅游2020校招笔试的回忆版题目发给我让我帮他捋一捋复习方向。我把整套题过了一遍最大的感受是这套笔试题考的不是你会背多少概念而是你有没有真正理解数仓从业务需求到数据落地的完整链路。尤其是最近“用户订单分析数据仓库”“维度表和事实表”这类热词频繁出现说明行业对校招生的要求越来越明确——不是招一个只会写SQL的取数机器而是招一个能理解数据模型、会做数仓设计的准工程师。接下来我会从题型构成、维度建模、SQL实战、备考经验四个角度做一次完整复盘。别看这套题标着2020年这类校招笔试的底层逻辑到现在依然适用甚至可以说把热点里的“核心维度表和事实表”吃透比盲目刷一百道面试题都有用。1. 拆解搜狐畅游笔试数据仓库开发工程师到底考什么1.1 题型构成与考察逻辑校招笔试的编制思路通常不是“一套题定生死”而是用综合题过滤一批人再用专业题筛选出真正有数仓感觉的候选人。搜狐畅游这套数据仓库开发工程师的卷子按网上回忆版和同类游戏公司笔试题的常见结构来看大体可以分成这么几块题型考察点常见形式数仓基础概念维度建模、事实表与维度表区别、数仓分层、ETL流程选择、填空、简答SQL手写窗口函数、留存率、分组TopN、连续登录、聚合统计手写SQL给表结构和数据数仓建模设计给定业务场景设计事实表、维度表、分区策略设计题需要画出表结构或写建表语句业务分析指标口径、数据质量、埋点日志和订单数据关联主观题给出分析思路这套结构看起来四平八稳但真正的筛选点在后面两类题。基础概念题大家复习一下都能答出个大概SQL题很多人也能写出来但写出来的SQL是不是能处理重复数据、是否考虑了分区裁剪、遇到数据倾斜怎么办这些才是区分“背过题”和“真做过”的地方。说白了校招不可能指望你有一两年大厂数仓实战经验只能通过这些问题判断你有没有形成“从业务到表结构再到指标”的完整数仓思维。如果你能在设计题里答出“为什么这样设计”而不是只扔出一堆字段那在阅卷人眼里就已经高一档了。1.2 题目背后的岗位画像游戏数仓开发在做什么笔试考什么往往是由岗位日常做什么决定的。游戏公司的数仓开发日常工作可以概括成把散落各处的游戏埋点日志、订单流水、渠道数据、登录日志全部统一接入、清洗、建模、分层最终变成运营、策划、发行看得懂、查得快的报表和分析数据集。这就决定了笔试绝对不会考很难的算法也不怎么考JVM调优重点就是数据仓库建模和SQL能力。比如游戏运营每天要看的新增用户数、DAU、次日留存、付费率、ARPU、LTV这些指标背后全都依赖一张张事实表和维度表的合理设计。笔试里出现“新增用户次日留存偏低怎么从数据上定位原因”这类题本质上就是看你能不能把业务问题翻译成数据问题。再往深处说游戏公司比一般互联网公司更看重渠道数据和买量归因。一款游戏上线广告投放花出去几百万运营需要知道每个渠道带来的用户质量怎么样、付费能力怎么样。这背后就是用户维度、渠道维度、订单事实表、活跃事实表之间的交叉分析。所以笔试题经常拿“用户订单”做背景因为订单是游戏公司最核心的变现环节没有之一。2. 把用户订单拆成维度和事实游戏数仓建模的实战推演2.1 先定业务过程和粒度很多人一上手做设计题就急着列字段这是最大的误区。建模第一步是先定义“你究竟要分析哪条业务过程”。用户订单分析这个场景业务过程就是“用户在游戏内完成一次支付”。有了业务过程接下来就要定粒度也就是事实表里每一行到底代表什么。订单事实表的粒度通常是一行代表一笔支付订单。举个例子某玩家同一天早上通过iOS渠道充值了一个6元首充档晚上又通过官网活动充值了一笔98元档那订单事实表里就应该产生两行记录都关联同一个用户维度键但订单号不同、渠道维度不同、支付时间不同。如果你把粒度定成“一个用户一天一行”那这两笔钱就会被揉在一起渠道分析、档位分析、活动效果分析全都会乱掉。笔试题里粒度写没写清楚是最容易被扣分的地方。我见过很多候选人设计表的时候字段写得密密麻麻但问他一行的粒度是什么支支吾吾说不出来。实际上粒度写不明白后面所有统计逻辑都会飘。答题时第一行就写清楚“粒度每笔支付订单一行”这相当于给阅卷人一个定心丸。2.2 事实表度量指标的设计与选择事实表是数据分析的“主体”里面装的是业务过程产生的度量值。订单事实表的核心字段大致长这样字段类型字段示例说明维度外键user_id, channel_id, product_id, date_id关联用户、渠道、道具商品、时间等维度表退化维度order_id, order_no订单号直接放事实表方便查明细和去重度量字段order_amount, pay_amount, discount_amount, item_count订单金额、实付金额、优惠金额、道具数量状态字段pay_status, order_status, refund_status成功、失败、退款等状态用于口径过滤注意度量字段的“可加性”问题。订单金额、实付金额、道具数量都是可加性度量任意维度组合都能直接sum没问题。但比率类指标比如付费率、转化率就不能直接sum必须先算分子分母再相除。这种题笔试里经常挖坑比如让你统计各渠道总收入你直接sum一个“付费率”字段那就明显露怯了。还有一个隐蔽细节退单怎么处理。是支付成功后进入事实表退款时把状态置为已退款还是直接又插入一条负金额的抵消记录这两种方案在实际项目里都有人用但口径必须统一。如果笔试题给了状态字段答案里最好主动说明“只统计订单状态为支付成功的记录退款单用状态字段排除或者以负值冲减”这样能体现出你对数据质量的敏感度。2.3 维度表常用维度与缓慢变化维处理维度表是事实表的“通讯录”用来描述事实数据的角度。订单分析常用的维度表有这几种用户维度用户ID、注册时间、注册渠道、首次登录时间、区服、设备型号、新手引导完成状态。渠道维度渠道ID、渠道名称、渠道类型官方包/广告投放/应用商店/线下活动、推广活动归属。商品或道具维度道具ID、道具名称、档位、原价、现价、道具类型以及所属的礼包活动。时间维度日期、周几、是否节假日、是否活动日、所属自然周/月。维度表最难的点是缓慢变化维也就是SCD问题。举个游戏场景下的例子一个玩家一开始是通过广告渠道注册的后面被归因到另一个渠道渠道维度要怎么改如果直接覆盖原名那历史订单的渠道归属就全变了如果保留原值不改那后续分析又拿不到最新信息。实际中最常用的方案是拉链表通过增加生效时间、失效时间和当前标志位让维度表既能还原历史也能支撑最新状态的查询。笔试里如果出现“用户VIP等级持续变化订单数据要按当时VIP等级分析”这种题能想到用拉链表设计用户VIP维度基本就是加分项。另外订单号、支付流水号这类属性不需要单独建维度表直接退化放到事实表里既能减少join又能方便排查问题这也是维度建模里的经典设计。2.4 数仓分层设计在订单场景中的落地数仓分层几乎是必考题但在订单场景里怎么落地很多人只会背“ODS、DWD、DWS、ADS”这串字母不知道每层到底放什么。我用订单分析场景串一遍ODS层原样接入订单流水、支付回调日志、埋点事件日志尽量保持和源系统一致不做过多的数据清洗。DWD层订单明细表对ODS数据做清洗、去重、格式统一、枚举值规范补全用户维、渠道维等外键。这一层是事实表的真正落地位置粒度还是每一笔订单一行。DWS层按用户维度汇总的每日付费表、按渠道维度汇总的每日收入表、按道具维度汇总的销售统计表。这里是公共汇总层存储的是经过合理粒度汇总的指标。ADS层面向具体报表需求生成的数据比如运营看板要的“活动期间各渠道ARPU”或者是“大额付费用户榜单”。这里想特别强调DWS层的作用。如果每个报表需求都直接从DWD层拉数每一次都扫全量订单明细又慢又浪费资源而且不同报表算出来的口径还可能对不上。DWS层把高频指标提前算好业务方查询的时候直接按维度过滤聚合效率和口径一致性都会好很多。笔试设计题能写出这一层的设计思想说明你不是光会建表而是真的理解数仓分层的价值。3. SQL题拉开的分差数据质量与业务口径3.1 留存率计算一道典型的Hive SQL笔试改编题留存率是游戏数仓最经典的面试题笔试出现的频率也极高。题目通常给两张表一张用户注册表记录每个用户的注册日期一张活跃表记录用户每天的登录行为。要求计算某种渠道或全量新增用户的次日留存率。这类题本身不难但坑很多。先看一个标准写法Hive/Spark SQL语法都能跑-- 用户注册表user_reg(reg_date, user_id, channel_id) -- 用户活跃表user_active(active_date, user_id) with new_users as ( select user_id from user_reg where reg_date 2020-08-01 ), active_next as ( select distinct user_id from user_active where active_date 2020-08-02 ) select count(a.user_id) as new_user_cnt, count(b.user_id) as retained_user_cnt, round(count(b.user_id) / count(a.user_id), 4) as retention_rate from new_users a left join active_next b on a.user_id b.user_id;先说说为什么这么写。第一步先把“2020-08-01注册的用户”取出来得到新增用户集合第二步取“2020-08-02活跃的用户”并去重因为一个用户一天可能登录很多次不去重就会把留存人数算高第三步用left join把新增用户和次日活跃用户关联起来再统计人数和比率。这种题的加分点在于你能主动说明口径。比如“新增用户”的定义是注册成功就算还是需要完成创角才纳入统计“次日”是自然日还是按用户首次登录时间往后推24小时是否要剔除测试账号和内部账号。你在答案里写一句“按自然日统计且剔除测试账号”阅卷人立刻知道你在真实项目里待过而不是只会套模板。3.2 窗口函数三板斧连续登录、分组TopN、滑动计算窗口函数是数据仓库笔试的高频区连续登录、分组TopN、滑动计算这三类题基本是“必刷三件套”。先看连续登录。经典问题是“找出每个用户连续登录天数最长的区间”。核心思路是去重后用row_number()给每个用户的登录日期编号然后用登录日期减去编号得到一个“标记日期”。同一段连续登录的记录它们的标记日期是一样的。最后按用户和标记日期分组统计天数即可。这个巧妙点在于把“连续性”转化成了“差值相等”在笔试现场能写出这个思路的说明是真正练过窗口函数。再看分组TopN。比如“统计每个渠道收入排名前三的用户”只需要用row_number()或rank()按渠道分区、按收入降序排列然后取rn 3。注意row_number和rank的区别如果两个人收入一样row_number会随机分1和2rank会都给1然后跳过2。题目如果要求并列就要选rank。滑动计算比如“近7天每个用户的累计付费金额”用sum(amount) over(partition by user_id order by pay_date rows between 6 preceding and current row)就能实现。这道题考的不只是函数语法还考察你是否理解窗口的范围定义。总体来说窗口函数题没有太多捷径把执行顺序搞明白——先where过滤、再分组、再开窗——比背一百道SQL题都管用。3.3 笔试里最容易失分的脏数据与口径处理校招笔试很多时候不会给你一份“干干净净”的数据而是故意埋一些脏数据。比如订单表里有重复订单、有支付失败的记录、有测试账号的充值、有退款单。这种题想看你有没有真实的数据处理经验而不是理想化的“select sum(amount) from order”。我实际工作中就遇到过线上订单表里居然有超过10%的重复流水原因是支付回调的重试机制导致同一笔订单被写入多次。在这种数据状态下直接按订单号去重、保留每个订单最新状态的那条记录是必须有的操作。笔试里如果遇到类似表结构答题时第一句话就应该写明“先按订单号去重按支付时间取最新一条并过滤支付失败和退款记录再统计收入”。还有一个很多人忽略的点业务口径。比如“付费收入”到底是毛收入还是净收入是否剔除退款一个订单分了三期支付算一单还是三单这些口径不定义清楚SQL写得再漂亮也没用因为算出来的数字不一样。笔试阅卷人往往更看重你有没有主动定义口径的意识这比SQL语法对不对更能说明你的数仓素养。3.4 SQL之外的隐形加分项分区、压缩、数据倾斜有些笔试设计题不要求你真跑一个SQL但你可以在方案里顺手写出工程化的细节这是隐形加分项。比如订单表规模巨大该怎么设计分区比较常见的是按天分区数据量特别大时再考虑按渠道或业务线做二级分区。存储格式上生产环境一般用ORC或Parquet配snappy或zstd压缩能大幅度减少扫描量。笔试答题时加一句“采用ORC格式按天分区存储”会显得你懂真正的生产环境而不是只会写demo。另一个高频考点是数据倾斜。游戏数仓里“官方包”这种渠道用户量极大join的时候很容易把某个reduce任务压垮。常见的解法包括大key加随机前缀打散然后再做二次聚合或者利用map join让小表直接加载到内存避免shuffle再或者先用过滤条件把大部分数据剔除再join。能把倾斜问题讲出两三招的人实际工作里大概率已经处理过真实数据了。4. 从笔试到入职数据仓库开发岗的备考路线与实战心得4.1 知识框架搭建与资料选择如果你现在正准备校招想体系化地复习数据仓库方向我建议按四个阶段来安排时间。第一阶段是数仓基础核心就是数仓分层、维度建模理论、事实表和维度表的设计方法。这阶段推荐《数据仓库工具箱》也就是Kimball那本经典书重点看维度建模的部分不用从头啃到尾把维度和事实的设计准则看完配合例子动手画一遍表结构比只看书强很多。第二阶段是Hive和Spark SQL重点练窗口函数、复杂查询、UDF/UDAF的基本写法。这个没有捷径就是刷题但刷完每道题最好都记一下这题的“考点关键词”比如“distinct去重”“row_number用于连续问题”“left join算留存”等方便考前快速过。第三阶段是真实场景的建模练习可以找一个订单数据自己设计一套从ODS到DWS的表结构再把几个核心指标的SQL写出来。这是笔试设计题的关键对应能力也是面试时能拿出来讲的项目素材。第四阶段是周边知识包括调度工具Airflow/DolphinScheduler的基本原理元数据和数据血缘的概念数据质量监控的常用手段。这部分笔试不一定考面试却大概率会聊到。4.2 做一次“从零到一”的建模练习我给所有准备数仓岗笔试的同学都提过同一个建议找一个业务场景把整个数仓设计流程完整走一遍。最简单也最贴近笔试热点的场景就是“用户订单分析”。具体做法大概是这样的先明确需求比如运营要看每天不同渠道的付费金额、订单数、付费用户数和客单价接着按业务过程确定粒度设计DWD层的订单事实表字段包括订单号、用户维度外键、渠道维度外键、时间维度外键、订单金额、实付金额、支付状态再设计用户维度表、渠道维度表和时间维度表把每个字段的类型、含义、主键都列清楚最后写出两三条统计SQL分别把“各渠道日收入”“各渠道付费用户数”“按用户维度汇总的月付费金额”算出来并说明这些SQL应该挂在DWS层的哪张汇总表上。这套练习做完你会发现笔试设计题基本就是这套流程的简化版。更重要的是你能理解为什么事实表要存度量值、维度表要处理缓慢变化维、分层要建在什么位置这些是背概念背不出来的。4.3 我复盘笔试时发现的三个典型错误带过不少简历和面试也批过大大小小的笔试记录我发现准备数仓岗的人容易踩三个坑。第一个坑是只写表结构不写粒度。很多人设计订单事实表字段写得满满当当但一问他这一行代表什么支支吾吾说不清。笔试答题时开头就把“每行代表一笔支付订单”写清楚是体现建模基本功最简单的一步。第二个坑是把业务属性一股脑塞进事实表。比如把优惠券ID、活动ID当作字段直接放事实表看起来能查但这其实是维度属性应该通过维度表外键关联而不是在事实表里存一堆业务代码。这样设计会导致后续维度更新时事实表跟着遭殃维护成本极高。第三个坑是只看重“写SQL”不看重“翻译需求”。实际上入职后你每天要接到的需求大多是运营的一句话比如“帮我看下最近活动哪个渠道拉新效果最好”。这句话翻译过来是要先定义活动期、再定义拉新、再按渠道分组、再对转化和留存做对比。笔试里的业务分析题就是在模拟这种场景。前期把这种翻译能力练好入职适应期会短很多也更对面试官胃口。4.4 真想进游戏公司数仓还要补什么如果目标就是搜狐畅游这类游戏公司除了通用的数仓知识我建议再重点补几个游戏行业特有的话题。首先是游戏埋点。游戏客户端会上报海量事件比如注册事件、创角事件、登录事件、关卡事件、新手引导完成事件、支付事件。这些事件数据怎么组织成事件表和用户行为明细表是游戏数仓绕不开的设计点。你会看到很多游戏公司的事实表不只有订单一种还有大量行为事实这是和电商数仓很不一样的地方。其次是LTV和ROI。游戏公司对买量投放效果极其敏感所以数仓要为渠道归因、LTV预估、ROI分析提供基础数据。了解用户生命周期价值这个指标的计算逻辑以及渠道归因的基本方案面试聊起业务场景会非常有优势。最后是离线和实时的边界。校招笔试一般只考离线数仓但游戏公司对实时指标的需求越来越强烈比如实时DAU、实时流水、活动实时战报。提前了解Flink、Kafka的基本概念以及实时数仓和离线数仓的架构差异哪怕只是能说出分层思路也会在面试中成为亮点。最后说一点个人体会。当年我准备笔试的时候也走过一段刷题刷到麻木的路后来真正入职做数仓才发现最好的复习方式不是把题库背完而是把“一份订单数据从产生到变成运营报表”的整个过程亲手做一遍。你越理解业务方怎么用数据就越知道维度表和事实表该怎么设计越知道分层该怎么搭。希望这份复盘能帮你把复习重点从“背概念”转到“建模型”上在笔试里写出让阅卷人眼前一亮的答案。
返回列表