ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

货拉拉大数据中心笔试题复盘:SQL与数仓建模的实战要点

2026/8/29 11:35:19 拓冰建站 浏览量
货拉拉大数据中心笔试题复盘:SQL与数仓建模的实战要点 “货拉拉2018秋招大数据中心笔试题”——单看这个标题可能觉得是一份过期真题没什么参考价值。但我在准备秋招时正好卡在那个时间节点这份笔试给我的冲击相当大。它没有堆砌偏题怪题而是把Hadoop、Spark、数据仓库建模和实际物流业务绑在一起考察的是“你能不能直接用数据解决业务问题”。后来我入职做了一段时间大数据开发再回头看这份题才明白当年很多答案其实只答到了表面。这篇文章会把题目按类拆开结合出题意图和我的踩坑复盘给准备大数据岗位面试的朋友一份能落地的参考。我不可能把每道题原封不动背下来毕竟过去几年了。但当时考完和几个同学对了答案也和一位参与出题的面试官做过交流还原出来的题型结构和核心考点是可信的。如果你是准备校招或跳槽的数据岗候选人这篇复盘值得完整看一遍。1. 一份物流大数据笔试的“考察地图”货拉拉想招什么样的人1.1 笔试环节在整个秋招流程里的定位秋招笔试不是用来筛天才的它最大的作用是快速排除“简历很漂亮但基本功不扎实”的人。货拉拉大数据中心2018年那场笔试时长90分钟题量不算大但覆盖面非常宽选择题考基础概念编程题里既有SQL也有算法最后还有一道数据仓库建模的开放题。如果你只看岗位JD会以为重点在Spark、Hive这些组件实际上试卷里大量题目都在考察“能否把业务问题翻译成技术方案”。这个定位非常重要决定了你复习的时候不能死啃底层源码也不能只刷LeetCode。我当时犯过一个错误临考前一周还在猛刷MapReduce shuffle阶段的源码细节结果试卷上只在选择题里带了一道关于shuffle的简单判断题真正的分数大头是SQL和建模分析。笔试的目的不是考倒你而是看你在有限时间内能不能稳定输出常用技能所以它的题目往往偏重通用性和方法论而不是刁钻冷门。1.2 大数据中心的技术栈与考察范围推测从题目内容可以反推货拉拉大数据中心当时的技术栈Hadoop生态是绝对主角HDFS、MapReduce、Hive、Spark都有涉及流计算考了Kafka和Spark Streaming的简单概念没有出现Flink。数据仓库部分考察了维度建模和分层设计这和当时多数互联网公司数仓团队的要求一致。由于货拉拉是货运物流平台订单派单、司机履约、用户行为这些数据天然带有空间和时间属性所以SQL题里出现了“按城市统计”“司机活跃区间”等场景。从岗位要求来看他们希望候选人具备三种能力第一扎实的工程基础包括数据结构、Java或Scala编程第二大数据组件的基本使用与原理理解至少要知道数据倾斜怎么处理第三数据建模和业务分析能力能理解核心指标的定义和口径。这三点基本就是那场笔试考察地图的三大板块下面的复盘也按这个逻辑展开。1.3 业务场景驱动的出题逻辑货拉拉的主营业务是同城货运撮合业务角色包括用户端、司机端和平台运营。2018年正是补贴大战火热的时候增长、完单、留存是三个最核心的分析方向。笔试出题人很聪明把业务抽象成了几道纯技术题例如“统计每个城市近30天完单量Top100的司机”看起来是SQL题背后其实是城市维度下的TopN分析而“求用户连续N天下单的最大天数”其实在考察留存和活跃的分析基础。这种出题逻辑对候选人有很强引导性你不需要了解货拉拉的商业模式但必须具备把“业务问题转化为数据计算逻辑”的能力。我后来在真实工作中发现这恰恰是大数据工程师日常做得最多的事。笔试里那道建模题直接给出了用户、司机、订单三张业务表要求设计数仓DWD和DWS层的表结构实际上就是面试官在日常工作中的简化缩影。2. 基础编程题复盘SQL和数据结构的必拿分项2.1 经典SQL题司机完单量TopN与连续参与时长统计笔试中有一道SQL题我印象很深给一张司机订单表包含司机ID、城市、订单创建时间、完单时间、订单状态要求统计每个城市在2018年8月完单量排名前100的司机及其完单量。这个题就是经典的分组TopN核心写法是用窗口函数。我当时的答案类似下面这样SELECT city, driver_id, order_cnt, rk FROM ( SELECT city, driver_id, COUNT(*) AS order_cnt, ROW_NUMBER() OVER(PARTITION BY city ORDER BY COUNT(*) DESC) AS rk FROM driver_order WHERE order_status finished AND finish_time 2018-08-01 AND finish_time 2018-09-01 GROUP BY city, driver_id ) t WHERE rk 100;这道题不难但有两个隐藏坑。第一是订单状态过滤如果算错把未支付订单也算进去结果会偏大第二是从表字段里提取月份的写法如果用substr会有性能问题而且容易忽略时间字段类型最稳妥的做法是直接使用时间范围条件这样还能利用分区裁剪。连续变量题考的是“司机连续N天有完单记录的最大天数”比如判断每个司机在8月最长的连续出勤天数。经典做法是用排名减日期法按司机分区按日期排序得到rank用日期减去rank得到一个伪日期相同伪日期就是连续的。大致SQL如下SELECT driver_id, MAX(consecutive_days) AS max_consecutive_days FROM ( SELECT driver_id, dt, DATE_SUB(dt, rn) AS grp FROM ( SELECT driver_id, dt, ROW_NUMBER() OVER(PARTITION BY driver_id ORDER BY dt) AS rn FROM ( SELECT DISTINCT driver_id, dt FROM driver_order WHERE order_status finished ) t1 ) t2 ) t3 GROUP BY driver_id, grp;这里一定要先对不同日期的完单做去重否则同一人同一天多单会被当成多天导致连续天数虚高。当年我就在这个细节上翻过车最后统计出来的结果和实际业务对不上。2.2 高频数据结构题TopK与滑动窗口的变形笔试算法部分没有为难人考了经典的海量数据TopK和一道滑动窗口变体。TopK题要求从一亿个整数里找出最大的100个数限制内存。标准思路是用大小为100的最小堆先填充100个元素然后每个新数如果大于堆顶就替换再调整堆复杂度O(N log K)。Java里直接用PriorityQueue实现简单可靠。这道题很多人能说出思路但手写时出bug的地方在于堆里存的是最大值还是最小值堆顶是什么意思如何初始化。我见过同学把最小堆写成最大堆结果取出来的前100个是“刚好最小的第100个以后的数”完全反了。这里要理解维护一个最小堆堆顶是当前Top100里最小的数如果新数大于堆顶说明这个新数有资格进入Top100同时要踢掉当前Top100里最小的那个数也就是堆顶。滑动窗口那道变体是给定一个整数数组和窗口大小k输出每个窗口最大值。这题最优解是用双端队列队列里存下标保证队首永远是当前窗口最大值的下标。核心代码不复杂但边界条件很容易漏尤其当窗口滑动时队首下标已经小于当前窗口左边界时要弹出。这道题在LeetCode上是Hard难度实际上思路理顺后就是几行代码。笔试时我用了暴力法嵌套循环数据量小能过但面试官后来告诉我他们更想看到O(N)的解法。2.3 基础题作答的防坑细节基础编程题最怕的不是不会而是“会但做错”。我总结了几个笔试时常见的丢分点SQL里能写窗口函数就不要用自连接写错了性能差阅卷人也会觉得你不够熟练算法题先确认输入规模和数据范围再选方案不要一上来就写堆排序手写SQL必须注意字段类型和NULL值处理COUNT(字段)会自动跳过NULLCOUNT(*)不会时间不够时优先把思路写出来再补代码阅卷一般会看关键逻辑给分。这类的确不是高端技术但在笔试场景里它们就是你和别人拉开差距的地方。基础题是整个试卷的“必拿分项”因为后续大数据组件和建模题更开放分数有波动如果基础题都丢分大概率会被淘汰。3. 大数据组件与架构题从原理到实战的血泪教训3.1 Hadoop与Spark原理题背后的考察点选择题里考了MapReduce的shuffle过程、Spark的宽窄依赖、RDD血缘关系、Kafka的消费者组机制。这些知识点都是大数据开发面试的常客但货拉拉这套题有个特点它不会直接问“shuffle分为哪几个阶段”而是给一个场景问你“这个操作会产生几个stage”或者“下面哪个操作会引起shuffle”。这意味着你需要理解原理而不是背概念。比如有一道题问Spark中groupByKey和reduceByKey的区别哪个更好表面上是考两个算子实际面试官想考察你是否理解Map端合并combine对数据量的影响。reduceByKey在map端先做一次聚合能大幅减少shuffle数据量而groupByKey直接把所有原始键值对发到下游。在写代码时能用reduceByKey的地方尽量不要用groupByKey。我当时把区别和性能影响写完后又补了一句“如果key分布特别不均匀reduceByKey也可能遇到数据倾斜”这算加分项因为这道题其实在暗示数据倾斜的概念。HDFS原理题考了副本放置策略第一个副本放在客户端所在节点第二个副本放在不同机架的节点第三个副本放在与第二个相同机架的不同节点。这个问题看起来是死概念但出题人加问了一句“为什么第二个副本要放在不同机架”这就牵扯到机架故障容灾和带宽权衡。答到“防止整个机架故障导致数据丢失”还不够最好补一句“机架间数据传输会消耗带宽所以第三个副本选择同机架不同节点来平衡可靠性与性能”。3.2 数据倾斜问题的完整解答路径数据倾斜是大数据笔试和面试里最常出的场景题货拉拉这套题也不例外。题目给了一个Spark作业统计司机订单量按司机ID聚合但部分大司机订单量极大导致某个reduce任务运行特别慢让你给出解决方案。我当时写了好几条现在复盘下来可以整理成一套完整解答第一定位倾斜。通过Spark UI查看某个stage里任务的输入数据量差异如果某个任务输入远大于其他任务基本可以确认发生了数据倾斜。笔试不需要你写UI细节但提到“先在UI趋势中看任务耗时和输入数据量”会让阅卷人觉得你有实战经验。第二加盐随机前缀解决。这是最常见的方法思路是把key加上随机前缀打散再分两步聚合。具体到“按司机ID聚合订单量”这个场景可以先给每个司机ID加上一个0到n的随机数做一次聚合然后去掉前缀再做二次聚合。这个方案能解决数据倾斜但要注意随机前缀的基数n要足够大否则还是可能斜。代价是数据量膨胀n倍。第三过滤异常key。有些倾斜不是业务正常产生的而是爬虫或脏数据导致的比如某个null值或空字符串占据了大量数据。如果倾斜key是这种无意义值最好的办法不是加盐而是直接过滤掉。当时我就想到过滤null还专门写了一句“需要和业务确认空值是否有统计价值”。第四使用Broadcast Join替代Reduce Join。如果一个大表和一个小表join时出现倾斜可以把小表广播到每个executor避免shuffle。用Spark写就是broadcast(hashTag)。这种办法对维表join特别有效比如订单表join城市维表直接把城市维表广播出去并行度立即提升。我把这些方案都写上去之后又加了一句“要根据倾斜key的性质选择不同方案而不是盲目加盐”这大概是我笔试里写得最像“有经验的人”的一句话。3.3 架构设计题百万级订单实时与离线链路怎么画这套笔试题有一道大题是画架构图用的是文字描述加箭头假设货拉拉每天有百万级订单需要设计一条离线分析链路和一条实时监控链路数据源是MySQL业务库和埋点日志目标是为BI报表和实时大屏提供数据。这道题考察的是全局架构视野。我当时用了经典Lambda架构思路实时链路和离线链路分开最终在服务层合并。离线链路大概画成业务库和日志 - Canal采集MySQL binlog - 落入HDFS - 用Hive/Spark进行ETL - 数仓分层ODS/DWD/DWS/ADS- 同步到MySQL/ClickHouse - BI报表。实时链路业务库binlog或日志 - Kafka - Spark Streaming/Structured Streaming - 实时计算指标 - 写入Redis/ES - 大屏接口读取。要明确画出数据分层并且解释每一层的作用。其实面试官更关心你对“离线实时一体化”的理解所以不能只画两条平行线要在最后说明“离线任务是小时级或T1实时任务是秒级两者在DWS层的指标定义必须一致”这就是从经验出发拔高回答。关于工具选型我当时写的是Spark Streaming因为在2018年Flink还没有像现在这么流行。如果你现在回答这道题完全可以直接说Flink。但要注意笔试要看时代背景不是越新越好而是你是否能理解实时计算的核心是“事件时间、窗口、水位线、状态管理”这些概念而不是套一个框架名词。4. 数据仓库建模题物流场景下最难啃的骨头4.1 从“货拉拉”业务出发维度和事实怎么选笔试最后一道开放题是给出用户表、司机表、订单表、支付表要求设计数仓分层并给出DWD和DWS层的表结构。这道题没有唯一标准答案但特别能看出候选人有没有真实建模经验。我当年答得中规中矩后来工作做了几张数仓模型才体会到当时漏掉了多少细节。先说维度怎么选。订单表作为核心事实表维度至少包括用户维度、司机维度、城市维度、时间维度、订单状态维度。这几个维度缺一不可。用户和司机要区分开因为货拉拉的平台里二者是不同角色但本质上都是“人”简历里很多新人会犯的错误就是只建一张用户维表没想清楚司机和用户其实有各自特殊属性比如司机有车型、常驻城市、认证类型用户有企业或个人标签这些属性在建维表时要区分。事实表的选择要看业务粒度。订单事实表明确为“每笔订单一行”这是最细粒度。对于支付信息如果一笔订单可能有多个支付事件部分付款、退款支付可以单独建模成累积快照事实表而不是简单地把金额字段塞进订单表。至于分层我写的结构是ODS层原始日志和业务表原样同步不加清洗。DWD层对ODS做清洗转换统一字段格式比如把订单时间拆成日期和小时把城市ID关联到城市名称清理无效数据。DWS层按主题汇总比如“司机每日完单汇总表”“城市每日交易汇总表”。ADS层面向具体报表应用比如“运营团队看的城市日报”。这个分层方案在所有互联网公司都类似但笔试题里要写出“为什么这样分层”。我当时的理由有三个隔离原始数据减少重复清洗明确定义中间层让下游指标口径一致权限和血缘更清晰。4.2 拉链表和累积快照事实表在订单场景的应用笔试的附加题里有一个小问问如何保存司机星级和常驻城市的历史变化。这个问题现在看就是典型的拉链表场景。我当时只写了“加生效时间和失效时间两个字段”但没解释怎么查询历史某个时间点的状态。现在把完整思路记录下来。拉链表的核心是在DWD层建一张维度表包含driver_id, star_level, city_id, start_date, end_date, is_active。每天用业务库里最新的数据与昨天全量做对比新增和变化的记录插入新版本同时更新旧版本的失效时间。查询时用WHERE start_date 2018-08-20 AND end_date 2018-08-20就能取到当时状态。这种设计在数据量较大、变化频率较低的场景下非常划算。累积快照事实表用来跟踪一个流程的多个状态变化时间。比如订单从创建、支付、司机接单、完成到取消每个状态都有一个时间字段事实表一行就是一笔订单包含order_create_time、pay_time、accept_time、finish_time、cancel_time。这样在计算“从下单到完单平均耗时”时就不用join多张表直接在同一条记录里做时间差。笔试里订单和支付如果分开建模最后还是要回到订单事实表做累积所以我在支付表设计里写了这个思路阅卷人应该能看出我理解状态流转。这里有一个很容易被忽略的点状态时间字段允许NULL。比如一笔订单还没支付那么支付时间就为空。在写加工SQL时必须用MAX(if(condition, time, null))这类写法把状态时间填到对应列不能用简单的聚合把这个字段丢掉。4.3 指标口径不统一的坑建模题还有一个陷阱一张汇总表里不同部门对“完单量”有不同定义。运营觉得司机点击“完成订单”就算完单财务觉得收到用户支付才算完单数据分析组可能又要求排除异常订单。笔试题目没有明说但在一个“城市每日订单汇总表”的字段设计里我写了“order_cnt”字段后面有人问这个口径是什么我就懵了。一个合理的设计是在DWS层就把业务口径固化成多个字段例如order_finish_count司机操作完成口径、order_paid_count用户支付口径、order_valid_count去掉取消和异常后的口径。每个字段都加注释说明口径来源。这样做的好处是下游直接用字段名就能对齐口径不需要反复解释。如果只建一个order_cnt后面必然会出现不同部门取数结果不一样然后再回来吵架。这道题给我的启发是数据建模不光是建表还要建立“指标字典”。笔试虽然不会让你写完整的字典但你可以在字段注释里体现这种意识。我当时写表结构时每个关键字段都加了comment这应该是加分项。5. 复盘与长期建议笔试之后成长才刚刚开始5.1 站在出题人角度反推复习重点复盘这份笔试题我最大的感受是出题人不是在考“你背了多少知识点”而是在考“你有没有做过真实项目”。因为真实项目的核心不是会调API而是知道什么时候用Hive、什么时候用Spark SQL、为什么离线用分区分桶、实时为什么选Kafka和Flink。这套题里的SQL题和建模题基本上就是大数据开发日常工作的简化版。如果准备类似的大数据中心笔试建议从三个方向准备第一SQL必须练到条件反射。分组TopN、连续问题、留存计算、窗口函数、行转列这些题型要多练。推荐直接用LeetCode数据库题和笔试难度差不多。第二大数据组件原理不能只停留在“用过”。至少要能回答出Spark作业提交流程、宽窄依赖、shuffle机制、HDFS读写流程、Hive的元数据存储、Kafka的ISR机制。不用背源码但要能画图讲清楚。第三数仓建模需要动手设计一次。不要只看书可以找一个你熟悉的业务比如外卖、电商、打车自己定义业务过程和维度建一套完整的数仓分层表。面试官一旦问你建模细节你会发现设计一套表远比想象中复杂。5.2 关于货拉拉这份笔试我还想说几句很多人觉得2018年的笔试已经过时不值得看。但恰恰是这种“不追赶新技术”的题目反而最能看出基础能力。Spark Streaming那题虽然现在大家都用Flink但背后的实时流处理思想没有变。数据倾斜问题更是直到今天都是高频面试题。再看建模题只要有数据团队就会需要理解维度和事实的人。从我个人经验来说笔试完之后一定要做一件事把所有错题和卡壳题整理成一个“错题本”并且给每道题补充“出题人想考什么”和“真实工作里什么时候会遇到”。比如我整理数据倾斜时就联想到一次线上任务跑了几小时没跑完最后用加盐和过滤空值解决的问题两者一对应知识就牢固了。最后分享一个我自己验证过的方法做笔试题时如果时间允许尽量把你的思考过程写在题目旁边。比如SQL题我会在写代码前先写一句“先按城市分组再按完单数排序取前100”。笔试不是机器阅卷时这些思路能帮阅卷人理解你的逻辑即使代码有小错也可能给你过程分。更重要的是这个习惯一直沿用到我现在的工作中每次写复杂逻辑前先写注释回头维护代码时会感激当年的自己。如果你正在准备大数据岗位希望这份复盘能帮你在笔试环节少踩几个坑。题目本身会变但基础能力、建模思维和业务理解永远是核心把这些练扎实不管哪一年的真题都不会难倒你。