准备校招笔试的时候,刷往年真题是最省力的一条路,尤其是像B站这种业务场景鲜活的互联网公司,笔试题往往不是单纯考背诵,而是把知识点藏在具体的业务场景里,看你能不能把底层原理讲清楚。这篇文章就围绕B站2020校招数据开发方向笔试卷(二)的核心题目,把数据开发岗位笔试里最高频的考点、容易踩的坑、以及通用的答题思路全部拆开聊一遍。无论你是正在准备秋招的应届生,还是想转行大数据开发的工程师,这套卷子背后涉及的SQL窗口函数、Hadoop/Spark原理、数据仓库建模、数据倾斜调优等内容,都是面试场上绕不开的硬骨头。
1. 整张卷子的结构与考点分布
1.1 数据开发笔试到底在考什么
拿到一份笔试卷子,先别急着埋头做题,站在出题人的角度把整张卷子的结构看清楚,往往比盲目刷题更重要。以这套B站数据开发方向笔试卷(二)为例,它整体上可以分成四大板块:SQL与数据处理、大数据基础原理、数据仓库与建模、以及一小部分场景设计与编程题。
第一板块是SQL题,占比通常在三到四成,主要考察窗口函数、多表关联、聚合统计、时间函数处理这些日常数开工作中用到最多的能力。这一板块的题目一般会给出业务表结构,让你写SQL完成某个统计需求,或者反过来给你一段SQL让你判断输出结果。不管是哪种形式,考察的核心都是你对SQL执行逻辑的理解深度,而不只是能不能把结果跑出来。
第二板块是大数据基础原理题,涵盖HDFS、MapReduce、Spark、Hive、Kafka等组件的核心机制。比如HDFS的读写流程、MapReduce的Shuffle过程、Spark的宽窄依赖与Stage划分、Hive的底层执行引擎切换等。这些题目考察的是你是否真正理解了分布式计算的运行机制,而不是仅仅会用工具。
第三板块是数据仓库与建模题,常见考点包括维度建模理论的星型模型与雪花模型、事实表和维度表的区分、缓慢变化维的处理策略、数据仓库的分层架构等。B站的笔试尤其喜欢结合实际业务场景出题,比如视频播放、用户活跃、内容推荐这类具体业务,让你设计指标体系或者数据模型。
第四板块是场景设计与编程题,一般是一道算法题加一道场景设计题。算法题常见的有TopN问题、分组排序、UV去重统计、连续登录天数等;场景设计题则可能考察实时计算架构选型、离线数仓链路搭建、数据质量保障方案等。这类题目没有标准答案,更多的是看你解决问题的思路是否完整,有没有考虑到数据倾斜、延迟、准确性等工程落地问题。
1.2 时间分配与做题顺序的实战建议
笔试的题量通常在8到12道左右,个别卷子会有十几道选择题外加三到四道大题。这套卷子整体难度并不算特别高,但它的坑在于题干信息量偏大,业务描述篇幅长,容易消耗大量阅读时间。我见过不少同学在选择题上耗费过多时间,导致最后的大题只能草草作答,非常可惜。
我通常建议按“先SQL后原理再编程”的顺序来做。SQL题是提分最稳的部分,只要窗口函数用得熟、关联逻辑清晰,基本能拿到大部分分数。基础原理题中,MapReduce和Spark部分掌握好核心机制就能答个八九不离十,不必死记硬背太细节的参数。场景设计和编程题放在最后,因为这类题目需要更多思考时间,而且只要写了就有分,尽量保证拿到笔者的基础分。
另外一定要控制好每道题的时间上限。简单选择题不要超过两分钟,拿不准就先标记跳过,不要在一道题上死磕。大题建议按照分值比例来分配时间,一道20分的大题,至少要给到二十分钟以上的完整时间,否则根本来不及写清楚方案。
2. SQL题深度剖析:窗口函数与多表关联
2.1 窗口函数是送分题也是拉分题
在数据开发笔试里,窗口函数几乎是人手一道的必考题。这道题本身并不是为了难倒你,而是想确认你有没有真正理解开窗逻辑。以“计算每个视频类目下播放量排名前三的视频”为例,常规思路是先用类目分组再排序,但如果没有窗口函数,就得用子查询关联或者临时表来实现,写起来又啰嗦又容易出错。
窗口函数的核心语法是ROW_NUMBER() OVER(PARTITION BY ... ORDER BY ...)。这里最关键的是理解PARTITION BY和ORDER BY的执行顺序。很多人以为窗口函数是先分组再计算,实际上在Hive、Spark SQL以及MySQL 8.0中,窗口函数是在WHERE和GROUP BY之后执行的,PARTITION BY只是在已过滤和已聚合的结果集上做逻辑分区。这一点如果理解不到位,很容易在写复杂SQL时出现窗口范围超出预期的问题。
举例来说,如果需要按类目和日期两个维度同时分组排名,可以写:
SELECT category, video_id, play_cnt, ROW_NUMBER() OVER(PARTITION BY category, stat_date ORDER BY play_cnt DESC) AS rk FROM video_play_daily WHERE stat_date = '2020-06-01'这里PARTITION BY用了两个字段,表示在类目和日期组合的维度上各自独立排名。如果只按类目分组,就会导致所有日期的视频混在一起参与排名,统计结果就完全错了。
除了ROW_NUMBER(),笔试中还经常会考RANK()和DENSE_RANK()的区别。简单记忆:ROW_NUMBER()不管值是否相同都按行号排,RANK()相同值排名相同且会留下空位,DENSE_RANK()相同值排名相同且不跳号。比如播放量分别是100、100、80,三个函数的排名结果分别是1、2、3;1、1、3;1、1、2。这道题在选择题里出现频率极高,必须稳稳拿下。
2.2 JOIN的语义陷阱与Semi Join
多表关联在笔试中也占了不少比重,尤其是不同JOIN类型的选择。像LEFT JOIN、RIGHT JOIN、INNER JOIN这种基础题其实难度不大,真正的拉分点在于LEFT SEMI JOIN和ANTI JOIN的运用。
有一道经典题目是“找出有点击记录但无播放记录的视频”。很多人的第一反应是NOT IN,但在大数据场景下,如果子查询的结果集很大,NOT IN会因为NULL值问题产生语义错误,而且性能极差。正确思路是用LEFT ANTI JOIN,或者NOT EXISTS子查询。
我之前在实际项目里就踩过NOT IN的坑。某次做视频分发效果分析,需要找出曝光未点击的视频列表,当时直接用NOT IN套在几百万条点击记录上,跑出来的结果比期望值少了一大截。排查了半天才发现,点击表里存在NULL值,NOT IN遇到NULL时整个判断会变成“未知”,导致符合条件的记录被过滤掉。自那以后,凡是涉及“排除某个集合”的场景,我都优先使用LEFT ANTI JOIN,语义清晰而且更符合分布式计算的习惯。
笔试中关于JOIN的另一个容易出错的地方是大表关联时的谓词下推问题。如果写了WHERE条件对右表进行过滤,需要确认这个条件是在JOIN之前还是之后生效的。在Hive中,ON后面的过滤条件只对关联过程生效,WHERE后面的过滤条件则是在JOIN结果集生成后再过滤。理解了这个顺序,写出来的SQL才能保证结果正确。
2.3 连续值问题:从自关联到扩窗技巧
“连续登录N天”这类问题几乎是数据开发笔试的常青树,B站这套卷子里也出现了类似题型。这类题的核心技巧在于利用行号与日期差值的稳定性来生成分组标识。
具体思路是:先对每个用户按登录日期排序生成行号,然后用登录日期减去行号得到一个时间差值,同一个连续区间内这个差值是不变的。最后按照用户和差值分组,就能统计出连续登录的天数。
SELECT user_id, grp, COUNT(*) AS continuous_days FROM ( SELECT user_id, login_date, DATE_SUB(login_date, ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY login_date)) AS grp FROM user_login_log WHERE login_date >= DATE_SUB('2020-06-30', 29) ) t GROUP BY user_id, grp HAVING COUNT(*) >= 7这里有个前提需要注意:同一天多次登录要去重,否则行号会被重复记录干扰,导致差值计算错误。所以建议在子查询里先按用户和日期去重,再做窗口排序。这个场景在实际工作中也很常见,做用户留存分析、活跃度分层时都要用到类似思路,值得彻底吃透。
3. 大数据基础原理:从HDFS到Spark的底层逻辑
3.1 HDFS读写流程与副本策略
HDFS相关题目在基础原理板块里几乎必出。常见问法有两种,一种是描述读文件流程,另一种是描述写文件流程。很多人能背得出“Client→NameNode→DataNode”这个顺序,但细节一问就卡壳。
先说写流程。客户端发起写入请求后,NameNode负责校验权限和路径,并返回可用的DataNode列表,客户端将数据分块(默认128MB)后,以管道方式依次写入第一个DataNode、第二个DataNode、第三个DataNode。每个副本写完后会向上游返回确认消息,当所有副本写入成功后,客户端再通知NameNode提交元数据。
笔试中容易忽略的考点是机架感知策略。默认的副本放置策略是第一个副本放在客户端所在节点,第二个副本放在不同机架的节点,第三个副本放在与第二个副本相同机架的不同节点。这个策略的设计理念是兼顾容灾和写入性能:跨机架存放副本能防止整个机架宕机导致数据丢失,而在第二个副本所在机架放第三个副本则减少了跨机架的数据传输消耗。
读流程的核心则是就近读取。客户端先从NameNode获取数据块与DataNode的映射关系,然后根据网络距离排序选择一个距离最近的DataNode读取数据。这里“最近”不单纯指物理距离,而是按照拓扑距离计算,相同的机架优先,其次是同数据中心。
3.2 MapReduce执行机制与Shuffle的细节
MapReduce题目是拉开差距的重要环节。很多同学能画出Map和Reduce两个阶段的流程图,但对Shuffle这个过程的理解比较肤浅。Shuffle指的是从Map输出到Reduce输入之间的数据移动过程,它包含了分区、排序、溢写、合并、抓取、归并排序等环节。
笔试中常考的点是Map端的Shuffle细节。Map输出的数据首先会写入内存缓冲区,缓冲区默认大小是100MB,当写入量达到80%阈值时,后台线程会开始将数据溢写到本地磁盘。溢写过程中会执行分区操作和排序,如果配置了Combiner,还会在溢写时先做一次局部聚合,减少传输到Reduce端的数据量。
Combiner这块经常被误解,有人以为Combiner和Reducer是同一个东西。实际上Combiner只是在Map端做局部合并的优化手段,它必须满足一个前提:合并操作不能改变最终的计算结果。比如求和、最大值这些操作适合使用Combiner,而求平均值就不能直接用Combiner,否则结果会出错。曾有面试官问过“为什么求平均值不能用Combiner”,回答时要讲清楚:Map端对部分数据求平均后,Reduce端再把各个局部平均值相加求平均,跟全局所有数据一起求平均值的结果不一致。
另一个高频考点是Partitioner的默认策略。默认使用HashPartitioner,按照key的哈希值对Reduce任务数量取模,决定每条数据进入哪个Reduce任务。如果Reduce任务数设置不合理,比如设置成1或者远大于集群槽位数,就会出现严重的负载倾斜或资源浪费,这也是后续调优的一个重要切入点。
3.3 Spark的宽窄依赖与Stage划分
Spark相关的题目更偏向考察对计算模型的理解。其中最核心的就是宽依赖和窄依赖的区分,以及依赖关系如何决定Stage的划分。
窄依赖指的是父RDD的每个分区最多被子RDD的一个分区使用,比如map、filter、union这些算子。宽依赖指的是父RDD的多个分区的数据需要经过Shuffle后分发到多个子分区,典型的就是groupByKey、reduceByKey、join等算子,需要跨节点传输数据。Stage就是根据宽依赖来切分的,每遇到一次宽依赖就划分出一个新Stage,同一个Stage内的算子可以尽量在同一个节点上执行,不需要网络传输。
笔试中容易出错的地方是Spark SQL与Hive的执行引擎差异。同一份SQL在Spark上和Hive上的执行计划可能不同,因为Catalyst优化器的规则和Hive的优化策略不完全一样。如果题面问“为什么Spark SQL比Hive快”,不要简单归因于内存计算,更准确的说法是Spark能构建DAG,在内存中完成多个计算阶段的数据流转,减少磁盘读写和任务调度开销,同时Catalyst做了谓词下推、列剪枝等优化。把这两点讲清楚,得分就会比只说“Spark快因为不走磁盘”高很多。
3.4 Kafka在数据开发链路中的定位
Kafka在数据开发岗的笔试题中通常不会考太深,但一些基础概念需要掌握,比如Partition、Consumer Group、Offset等。经常出现的题目是“Kafka为什么能做到高吞吐”,这个问题的核心在于顺序写磁盘、页缓存、批量发送以及零拷贝技术。
其中零拷贝(Zero Copy)是一个高频考点,它通过sendfile系统调用把数据从磁盘文件直接传输到网卡,绕过了用户态缓冲区,减少了数据拷贝次数。传统的文件传输需要四次上下文切换和四次数据拷贝,零拷贝可以降低到两次上下文切换和三次以内的数据拷贝,这些都是可以直接答到卷面上的关键点。
另外关于消息可靠性保证,数据开发工作中经常设置为acks=all,代表写入所有副本成功后才返回成功,这样能最大程度上避免消息丢失,但同时也会增加延迟。笔试中如果遇到“如何保证Kafka消息不丢失”这类题,要从生产者、Broker、消费者三个层面来分析:生产者开启重试和幂等,Broker设置副本因子和ack策略,消费者手动提交offset并确保处理成功后再提交。
4. 数据仓库与建模:理论结合实际业务场景
4.1 维度建模中的星型模型与雪花模型
数据仓库建模这部分,B站笔试比较喜欢结合自身业务来出题,比如给一个视频播放事实表和用户维度表、视频维度表,让你判断模型类型,或者说明两种模型各自的优劣。
星型模型和雪花模型的主要区别在于维度表的规范化程度。星型模型中维度表是反规范化的,雪花模型则将维度表拆分为多个层级,消除了部分冗余。实际数仓开发中,星型模型使用更广泛,因为它查询性能更好、易维护性更强。
笔试中如果遇到“为什么大多数互联网公司选择星型模型”,可以从两个角度回答。一是查询路径短,模型层级少,生成的SQL执行计划更高效;二是维表变更时影响面可控,不需要跨多级关联修改数据。但要注意补充说明,雪花模型并非一无是处,在存储成本敏感的早期数仓中,它通过减少冗余能节省大量空间,只是在大数据存储成本不断下降的背景下,这种优势已经逐渐减弱。
4.2 事实表分类与累积快照事实表
事实表按粒度可以分为事务事实表、周期快照事实表和累积快照事实表。笔试中容易混淆的是周期快照和累积快照。周期快照是按固定时间间隔记录事实的累计状态,比如每天记录一次用户当前账户余额;累积快照则是记录一个业务过程从开始到结束的多个里程碑时间点,比如一个订单从下单、支付、发货、到确认收货的时间节点。
实际工作中,累积快照事实表通常用于需要跟踪业务流程进度的场景。我记得做过一个内容审核时效分析的需求,需要在数仓里建立一条审核事件的事实表,记录视频从提交审核到审核通过每个状态变更的时间点。如果用事务事实表记录每一次状态变更,查询当前状态和全程耗时就很麻烦;改成累积快照事实表后,每个视频一行记录,直接通过列字段算出每个环节的耗时,极大地简化了后续的分析逻辑。
面试答题时,如果能补充一句“累积快照事实表因为每个业务实体只保留一条记录,所以更新频率较低,一般只在状态发生变化时才更新”,会显得对建模理论理解更深。
4.3 数仓分层架构以及各层的职责边界
数仓分层几乎是笔试题中必考的基础题,常见分层为ODS、DWD、DWS、ADS。一般考察方式要么是让你说出各层的职责,要么是给一张表判断它应该属于哪一层。
ODS层是贴源层,与业务库做同步,保持原始数据不做太多的加工。DWD层做数据清洗和维度退化,将事实表和维度表统一到相同的粒度,本质上完成维度建模。DWS层是汇总层,面向主题做轻度的汇总,比如按天、按小时统计各种核心指标,这一层通常以宽表形式存在,直接服务上层应用。ADS层是应用层,面向业务方具体需求做定制化加工,输出报表或数据接口。
这里可以补充一个判断技巧:如果一张表粒度为明细行,那大概率在DWD层;如果粒度为某个维度的日汇总,那基本属于DWS层;如果表里的指标直接支撑业务报表,不再做二次加工,那就在ADS层。这套判断逻辑在笔试中非常实用。
4.4 缓慢变化维的常见处理方式
缓慢变化维(SCD)在建模题目中的出现频率也比较高,通常考察Type 1和Type 2两种策略的区别。Type 1是直接覆盖原有值,不保留历史,优点是简单,缺点是无法追溯历史。Type 2是新增一条记录,并增加生效时间和失效时间字段,通过版本号标记当前有效数据,可以完整保留历史状态。
笔试中常考的问题是“如何用Type 2处理用户所属等级的变化”。回答时要把字段设计说清楚:至少需要user_id、grade、start_date、end_date、is_current五个字段。每次等级变化时,将当前记录置为失效,新增一条历史状态为有效的记录。如果要查询某一天的等级状态,只需要判断该日期落在哪个生效时间内即可。
实际开发中还有一个隐藏点需要留意:全量同步和增量同步下SCD的处理逻辑不同。增量同步通常只更新变化的用户,而全量同步需要拿前一天快照和当天快照做差集,确定新增、变化、失效的记录,写起来麻烦得多。我在做会员等级维表时就遇到过这种问题,后来改成用拉链表的方式存储,每天记录一份当天的全量状态,虽然存储量大了一些,但查询逻辑简单可靠,也很值得推荐。
4.5 指标体系设计与业务口径统一
除了建模,指标体系设计也是数据开发笔试中容易出现的场景题。比如“针对B站视频作者,设计一套内容健康度指标体系”,这类题没有标准答案,关键是考察你是否有结构化思维。
建议从内容供给、内容消费、互动反馈、质量风险四个维度来搭建指标。内容供给关注视频发布量、过审率;内容消费关注播放量、人均观看时长、完播率;互动反馈关注点赞、投币、收藏、转发、弹幕数;质量风险关注举报率、违规率、限流率。每个指标都要明确统计口径,比如“完播率”是播放完成人数除以播放总人数,还是播放完成次数除以总播放次数,不同的口径会直接影响分析结论。
这类题目如果能给出指标定义表,分别列出指标名称、维度、汇总方式、统计周期,会显得非常有条理,面试官一眼就能看出你有实际做指标体系的经验。
5. 编程与场景设计题:拿到分的常见套路
5.1 TopN问题的多种解法
TopN问题是数据开发笔试中最常考的编程题,几乎每种语言、每种计算引擎都绕不开。常见的解法有四种:全局排序取前N、分组TopN、以及使用堆和Rank窗口函数。
全局TopN比较简单,直接ORDER BY后取前N条即可。但分组TopN就需要小心了,比如“按类目统计播放量前3的视频”,这类问题在MapReduce环境下,最简单的做法是自定义分区器+自定义分组比较器,把同一类目的记录分到同一个Reduce任务,并在Reduce端维护一个容量为N的最小堆。如果直接用Spark,则可以用window函数加filter,或者用groupByKey后在每组内排序取前N。
笔试中需要注意的是复杂度和性能优化。如果数据量极大,所有数据都集中到一个Reduce任务上就会发生数据倾斜,所以提前要通过设计分区键保证数据均衡。比如在分组字段后拼接一个随机数作为分区键,在Reduce端再按真实分组取TopN,这样可以显著缓解倾斜问题。
5.2 数据倾斜问题的排查与解决
场景设计题中出现“数据倾斜”的概率极高。问法通常是“某个Spark作业一直卡在99%,可能是什么原因,如何解决”。这道题考察的核心是你能不能系统地排查数据分布不均的问题。
先说排查思路。要先去查看Spark UI中各个Task的处理时间,确认是否存在大部分Task很快结束、少数Task长时间运行的情况,然后在数据中统计热点Key出现的频次。常见的热点key包括空值、默认值、某个特定业务维度过高的情况。
解决方案从四个层面入手:一是过滤掉异常Key,如果Key为null且业务上无意义,直接过滤;二是提高Shuffle并行度,比如给groupByKey或join算子手动指定分区数;三是两阶段聚合,先加随机后缀打散,再局部聚合一次,最后去掉后缀做全局聚合;四是如果倾斜发生在Join时,可以将小表广播到每个节点,避免Shuffle。
这里有一个实际案例。之前做一个订单分析任务,两个大表Join时,因为一个订单表里某个热门店铺的订单量占到了四成,导致这个店铺对应的Task严重拖慢整体进度。后来把大表的热点Key拆分成随机前缀关联小表的膨胀副本,倾斜问题直接解决,整个任务从四十分钟缩短到八分钟。这种经验写进答案里,会显得非常有说服力。
5.3 UV与去重统计的工程实现
UV(Unique Visitor)统计也是数据开发笔试中常见的大数据场景题,尤其是精确去重和近似去重的取舍问题。如果数据量在千万级别,可以用COUNT(DISTINCT user_id)直接统计,但如果数据量上亿甚至更大,精确去重的成本和性能都难以接受,这时就需要用近似算法。
HyperLogLog是业界最常用的近似去重算法,Redis中就有现成的实现,Spark的approx_count_distinct函数底层也是基于它。它的核心原理是用哈希函数将数据映射为二进制串,利用低位连续零位的最大长度来估算基数,存储空间极小,误差通常在0.81%以内。笔试中如果能解释清楚这个原理,并说出精确去重和近似去重的选用场景,基本就拿到大部分分数了。
还有一个高频题目是布隆过滤器,问法通常是“如何在实时计算中快速判断一个用户是否是新增用户”。布隆过滤器的思路是把数据映射到多个哈希位,位数组中的对应位置置为1,判断时只要有任意一位为0,就说明数据肯定不存在。它的优点是空间占用极小,缺点是存在误判率,且无法删除元素。实际实现时可以选择使用Redis的布隆过滤器插件,或者用Guava库中的实现。
5.4 实时计算场景与离线数仓链路的融合
实时计算方向的大题在B站笔试中出现概率不算低,一般会围绕实时指标计算或实时数仓架构来出题。常见问法是“从0到1搭建一个实时大屏系统,请描述技术选型和整体架构”。
回答这类题要展示清晰的架构分层,建议按以下链路来组织答案:数据接入层使用Kafka承接业务日志和埋点数据;计算层使用Flink或Spark Streaming进行实时处理;存储层根据不同需求选型,指标明细用ClickHouse、Doris,缓存加速用Redis;应用层通过WebSocket或轮询将结果推送到大屏展示。
计算层选型时要能说明为什么Flink更适合实时计算。Flink的优势在于原生流式计算、精确一次的状态一致性语义、毫秒级延迟,而Spark Streaming本质上是微批处理,延迟在秒级。如果业务场景对延迟要求很高,比如秒杀活动的大屏监控,Flink是更合适的选择;如果只需要分钟级延迟,Spark Streaming也能胜任。
实时数仓与离线数仓的融合也是近年来的热点。常见的做法是离线数仓照常走ODS、DWD、DWS、ADS的分层链路,实时数仓则复刻一套精简版分层,ODS层直接消费Kafka原始数据,DWD层做实时清洗关联,DWS层做实时指标汇总,最终写入OLAP引擎。这样既能保证离线报表的准确性,又能支撑实时大屏的延迟要求。
5.5 数据质量保障的完整方案
数据质量保障题近几年在笔试中的出现频率越来越高。问法一般是“如何保证数仓中每日报表数据的正确性”,或者“数据延迟导致数仓和线上数据不一致,如何设计校验机制”。
答题时可以分三个层次来展开。第一层是源头管控,包括埋点规范、数据接入校验、空值和异常值排查。第二层是过程管控,在数仓各层加工链路中增加数据质量监控,比如行数波动超过阈值就触发告警,关键字段的枚举值分布异常时自动阻断下游任务。第三层是结果校验,将数仓指标与业务库指标做交叉验证,比如每天的GMV与交易库汇总比对,差异超过千分之一就发出告警。
实际项目中我常用的一套做法是,在DWS层建一张指标校验表,定时任务跑完后自动比对主键唯一性、非空字段、汇总值与前一日波动幅度,所有校验规则都用配置化方式维护。这种方案不用写死代码,新增指标时只需要在配置表里追加一条记录,非常方便。答题时把这个思路讲出来,面试官会明显感受到你有实际工程经验。
6. 笔试中的高频失分点与实用避坑技巧
6.1 SQL语法细节:Hive和Spark SQL的差异
SQL题失分最多的原因往往不是逻辑不会,而是语法细节不兼容。同一个查询在Hive和Spark SQL中的行为可能有细微差异。比如在Hive中,FROM子句和SELECT子句中列别名的使用位置就不同,WHERE条件里不能直接使用SELECT中定义的别名,而ORDER BY则可以。
另一个容易翻车的是空值的处理。Hive中NULL参与算术运算的结果还是NULL,但很多人写IF(col != '1', 0, 1)时忽略了col为NULL的情况,导致统计结果出现大量0。正确写法是CASE WHEN col IS NULL THEN 0 ELSE 1 END。这类细节在选择题里非常常见,失分点很小但很致命。
另外在窗口函数中,ORDER BY和ROWS BETWEEN的使用也很容易出错。如果不加ROWS BETWEEN,SUM() OVER(ORDER BY date)会默认统计从分组起始到当前行的累计值;如果加了ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW,结果虽然相同,但语义更加明确。在需要计算滑动窗口均值时,ROWS BETWEEN 6 PRECEDING AND CURRENT ROW这种写法是必须掌握的,笔试很容易出一段类似SQL让你判断输出结果。
6.2 原理题的答题方法:从流程到原因
在大数据原理题中,不少同学只会写“是什么”,不会写“为什么”,这是最大的失分点。例如问“HDFS为什么不适合存储大量小文件”,很多人回答“因为小文件占用NameNode内存”,但不够完整。更完整的回答应该包含三个层次:第一,NameNode将文件系统的元数据存储在内存中,每个文件、目录和块大致占用150字节左右,大量小文件会耗尽NameNode内存;第二,访问小文件时需要频繁在DataNode之间切换,寻址开销巨大;第三,MapReduce处理小文件时,每个文件可能会被拆分到独立的InputSplit,导致MapTask数量激增,调度成本远高于计算成本。三层都答到,得分才会高。
同样的逻辑适用于“MapReduce为什么慢”这类问题。不要只回答“因为Shuffle需要排序”,要补充说明Shuffle过程中磁盘IO数量、网络传输消耗和排序开销,以及Task调度需要额外的时间,这样答案才立体。
6.3 卷面表达:思路比结果重要
笔试不同于面试,没有追问机会,所以在有限空间内把你的思路完整展示出来就显得格外重要。我批改过不少笔试问卷,最明显的感觉是:能拿到高分的答案,不一定是完全做对的那份,而是把思路和过程写得清清楚楚的那份。
比如编写SQL题时,就算最终答案没有跑通,也要把“先对数据做清洗去重→再按维度汇总→最后用窗口函数排名”这个思路写出来,阅卷人看到清晰的思路,即使细节有误也会给不少分。场景设计题更是如此,宁可把每一步的取舍理由写出来,也不要只写一句“用Flink+Flink SQL+Kafka+Doris”。
卷面的另一个加分项是写出方案的边界条件和优化方向。比如答“如何统计TopN视频”时,补一句“如果数据量极大,建议用近似算法或者预处理预聚合”,就能让答案从及格提升到优秀。
7. 备考数据开发岗的实战路线
7.1 知识点查漏补缺
准备数据开发笔试,最怕的是只刷题不补理论。SQL题可以靠刷题提升熟练度,但大数据组件原理必须建立系统性的知识框架。建议按照Hadoop生态组件为主线,逐个梳理核心概念和常见问题。我自己备考时的做法是,每个组件准备三个维度的问题:是什么、做什么、有什么坑。比如Kafka,“是什么”是分布式消息队列,“做什么”是解耦削峰、日志收集、实时计算数据源,“有什么坑”是消费堆积、分区顺序、重复消费。
数仓建模部分,建议把维度建模的理论书过一遍,重点理解事实表、维度表、SCD策略、粒度选择这几个核心概念。同时可以找一两个真实业务场景练手,比如设计一个电商交易分析模型,或者设计一个内容平台作者成长分析模型,按自己的思路画一张数据模型图,写清楚每张表的粒度、主键、字段和状态划分。
7.2 真题训练的正确姿势
真题训练不是简简单单把题目做一遍就结束,而是要复盘。每次做完一套题,至少要把错题和蒙对的题整理出来,分析错因是知识点不熟、读题不仔细,还是时间分配不当。对于知识点不熟的部分,要回到源码、书籍或文章里重新理解,而不是依赖题目的标准答案。
编程题部分建议按类型刷题,比如连续值问题、TopN问题、UV统计问题、数据倾斜问题各刷十道左右,直到能够不假思索地写出核心框架。因为笔试时时间紧张,如果还需要临时想思路,基本很难完整写出正确答案。
7.3 工程经验如何弥补
没有实习经验的应届生遇到场景设计题往往比较慌,这个可以通过平时学习和动手搭建来弥补。自己搭建一套简单的数仓项目,从数据采集、数据清洗、分层建模到报表展示,完整走一遍,哪怕数据量很小,也能让你对工程链路有真实感知。另外一个被低估的方式是阅读技术博客和源码解析类文章,了解业界在数据中台、实时数仓、数据治理方面的实践思路。笔试中的场景设计题,往往就是这些问题的高维变体。
刷了那么多真题,我最大的感受是:数据开发笔试考的不只是零散知识点的记忆,而是你在真实项目中面对一个数据需求时,能不能把链路理清楚、把技术选型讲明白、把潜在问题想到位。这套卷子里的SQL窗口函数、MapReduce机制、数仓建模、数据倾斜处理,每一个都是平时工作中天天用到的东西。备考阶段把这些基础打扎实,不仅为了过笔试,更是为了入职后能快速上手干活。按照本文的思路,把每个板块的核心考点再过一遍,把薄弱环节补起来,这套卷子就不会成为你秋招路上的拦路虎。