2023年腾讯音乐春招数据工程岗第二批笔试一次完整的复盘与拆解每年的三四月都是春招笔试的高峰期数据工程岗的笔试题型这几年变化其实不大但每家公司考察的侧重点差异明显。腾讯音乐的数据工程岗第二批笔试我在规定时间内完成了全部题目整体感受是SQL考察扎实大数据组件覆盖面广算法题不算难但需要细心。这篇文章把整场笔试从题型分布到具体解题思路完整复盘一遍也聊聊我在备考过程中的取舍和踩过的坑给接下来要参加同类岗位笔试的朋友一个参考。先说结论数据工程岗笔试和数据分析岗、后端开发岗有明显区别。数据分析岗更看重SQL灵活度和业务敏感度后端开发岗更看重工程能力和算法深度而数据工程岗位于两者之间——SQL必须熟练Java/Scala基础要会大数据生态组件Hadoop、Spark、Kafka、Flink的基本原理要清楚同时还会带一两道常规算法题。腾讯音乐这场笔试基本就是按这个框架来的。1. 笔试前的岗位拆解数据工程在腾讯音乐到底做什么在讲题目之前先聊一个很多人忽略的问题笔试其实是在筛选你适不适合这个岗位而不是单纯考你会不会写代码。理解岗位职责才能反过来推导笔试的重点。1.1 从岗位JD反推考察方向腾讯音乐旗下拥有多个音乐平台数据工程团队的核心工作大致分为几块一是音乐内容、用户行为等数据的采集与接入二是数据仓库的建模与ETL开发三是实时计算链路比如直播互动数据、播放量实时统计四是数据质量保障与治理。对应到笔试上数据仓库建模和ETL开发——这基本就是SQL的大本营所以SQL必考且占大头。实时计算链路——意味着Flink、Kafka相关知识会涉及。数据采集接入——Hadoop生态、Spark、Hive这些组件原理绕不开。而算法题更多是考察候选人的基本编程功底毕竟数据工程师日常也要写UDF、写Spark作业编程能力太弱是不行的。1.2 第二批笔试的场次特点同一家公司春招往往有多批笔试第二批有个特点题库已经跑过一轮题目难度和判分标准相对稳定而且和第一批存在一定程度的题目复用或变体。如果你认识第一批考过的同学能问到一些题型方向但题目细节通常会有调整所以不能寄希望于背题还是要实打实掌握知识点。另外第二批笔试的时间点通常比较尴尬——很多人的春招拉锯战已经打了一段时间状态可能没有第一批时那么饱满。这场笔试给我的教训就是无论之前面了多少家、笔试了多少场每一场都要当作独立的一场来对待心态上的疲态会影响时间分配和正确率。注意笔试只是筛选链的一环。腾讯音乐的流程一般是笔试通过后进入面试笔试成绩会直接影响面试官对你的初始印象尤其是SQL题目做得好不好面试中经常会追问笔试里的思路所以笔试不仅要写对还要能讲清楚为什么这么做。2. 笔试全流程复盘题型分布、时间压力与答题策略整场笔试时长120分钟题型分为四个部分单选题、多选题、SQL编程题、算法编程题。其中客观题大约占40%的分数编程题占60%这个比例说明公司更看重动手能力死记硬背概念拿不了高分。2.1 客观题考察范围大数据组件与基础理论单选题大概10道多选题5道左右覆盖范围很典型Hadoop核心组件HDFS读写流程、NameNode和DataNode职责、MapReduce的Shuffle过程SparkRDD的依赖关系窄依赖和宽依赖、Stage划分依据、Spark SQL的执行流程Hive内部表和外部表的区别、分区表和分桶表的适用场景、Hive SQL的底层执行引擎切换Kafka消息投递语义at-most-once、at-least-once、exactly-once、分区与消费者组的关系FlinkExactly-Once的实现机制Checkpoint 两阶段提交、窗口类型滚动窗口、滑动窗口、会话窗口Java基础集合类源码级别的简单考察、并发编程基础synchronized和ReentrantLock区别计算机网络TCP三次握手、HTTP与HTTPS区别这类基础题偶尔会出现多选题是重灾区。多选少选都不得分这就要求对概念的理解必须精确。我在多选上丢了几分原因不是不会而是对某些概念的边界条件记忆模糊。比如下列关于Spark Shuffle的说法正确的是其中有一个选项是Spark 2.0之后默认使用Sort-Based Shuffle这个表述本身正确但我当时犹豫了很久因为印象里还有Hash Shuffle的历史版本最终没有选它事后确认是选错了。经验刷题的时候不要满足于知道对了要达到知道为什么对、错在哪里的程度。多选题考察的往往就是概念的边界。2.2 时间分配策略编程题必须先做这场笔试我采用的策略是先花5分钟快速浏览全部题目然后立刻做两道编程题再回头做客观题最后留时间检查SQL题。原因很简单客观题不会就是不会纠结再久也没用而编程题就算一时没有思路静下心写也能拿部分分数。实际执行下来两道算法题用了约35分钟SQL大题用了约40分钟客观题用了约25分钟最后剩下15分钟检查。时间整体可控但如果先做客观题在多选题上多纠结几分钟后面编程题的节奏就会被打乱。这个策略还有个额外好处先把编程题做完心态上就稳了。笔试过程中最怕的就是前边耗掉太多时间后边被迫赶工一赶工就会犯低级错误。3. SQL编程题复盘电商场景下的多表关联与窗口函数实战腾讯音乐这场笔试的SQL题并不是围绕音乐业务出的而是给了一个通用的业务场景我记得是类似电商订单的场景包含用户表、订单表、商品表、退款表。三张表的结构大致如下用户表user_id、user_name、register_date订单表order_id、user_id、product_id、order_date、amount、status商品表product_id、product_name、category_id、price表结构不复杂真正的复杂度在问题本身。3.1 题目一计算每个用户的首单时间和首单金额这道题核心考的是窗口函数的使用。拿到题的第一反应可能是用GROUP BY MIN但要同时取出首单时间对应的订单金额就需要想办法关联回去了。我的做法是用ROW_NUMBER()按用户分区、按订单时间排序取排名为1的记录SELECT user_id, order_date AS first_order_date, amount AS first_order_amount FROM ( SELECT user_id, order_date, amount, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_date ASC, order_id ASC) AS rn FROM orders WHERE status paid -- 或根据实际业务过滤有效订单 ) t WHERE rn 1;注意ORDER BY后面除了order_date还要加上order_id作为次级排序条件目的是处理同一用户在同一时间下了多单的边界情况。虽然实际数据里同一秒下两单的概率不高但作为数据工程师写SQL要有这个意识——排序条件不唯一时结果就不确定。如果不用窗口函数可以用自关联或者先取MIN(order_date)再JOIN的方式但代码会更绕而且逻辑上容易出问题。窗口函数是数据岗笔试的必考内容ROW_NUMBER()、RANK()、DENSE_RANK()、LAG()、LEAD()、SUM() OVER()这几个必须烂熟于心。3.2 题目二计算每个商品类目的月销售额环比增长率这道题的价值在于考察两个点一是按类目和月份分组聚合二是环比增长率的计算。后者需要访问上一个月的数据在SQL中通常有两种实现方式LAG()窗口函数或者自关联。LAG()实现方式如下WITH monthly_sales AS ( SELECT p.category_id, DATE_FORMAT(o.order_date, %Y-%m) AS month, SUM(o.amount) AS total_amount FROM orders o JOIN products p ON o.product_id p.product_id WHERE o.status paid GROUP BY p.category_id, DATE_FORMAT(o.order_date, %Y-%m) ) SELECT category_id, month, total_amount, LAG(total_amount) OVER (PARTITION BY category_id ORDER BY month ASC) AS prev_month_amount, ROUND( (total_amount - LAG(total_amount) OVER (PARTITION BY category_id ORDER BY month ASC)) / LAG(total_amount) OVER (PARTITION BY category_id ORDER BY month ASC) * 100, 2) AS growth_rate FROM monthly_sales;有一个实现细节值得单独说明写LAG()的时候可以先不加默认值但实际业务中第一个月没有上期数据除以NULL会得到NULL这其实是合理的因为第一个月就没有环比。但有些题目会要求第一个月显示0或者不显示这时候可以用COALESCE(prev_month_amount, 0)处理或者直接过滤掉prev_month_amount IS NULL的行。这道题还隐含了一个表关联的能力订单表和商品表要JOIN一次才能拿到类目信息。JOIN条件要选中关联键product_id字段没写错这个基础能力不能失分。3.3 题目三筛选出连续3天都有下单的用户连续问题的SQL解法是数据岗笔试的高频考点几乎每家都会考。经典思路是先按用户分组去重日期然后用日期减去ROW_NUMBER()的序号如果连续做差后得到的是同一个日期。参考写法WITH user_dedup AS ( SELECT DISTINCT user_id, DATE(order_date) AS order_dt FROM orders WHERE status paid ), dated_diff AS ( SELECT user_id, order_dt, DATE_SUB(order_dt, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_dt) DAY) AS diff_date FROM user_dedup ) SELECT DISTINCT user_id FROM dated_diff GROUP BY user_id, diff_date HAVING COUNT(*) 3;这里有一个很关键的细节必须先对(user_id, order_date)做去重否则同一天下两单的用户直接用窗口函数计算会出现误判。我在练习阶段就犯过这个错当时拿到题想都没想就直接上ROW_NUMBER()结果ORDER BY的排序逻辑全乱了。连续问题是理解窗口函数和分组聚合相互作用的最佳练习题思路本身不复杂但要保证每一步都严谨。面试时如果你的答案里主动提到我先去重因为同一用户可能在一天内下多单面试官通常会很认可——这体现出了真实业务场景下的数据敏感度。3.4 SQL题失分点总结SQL题看起来简单真正丢分的往往是边角细节。我整理了一下这场笔试中可能丢分的几个位置排序字段不唯一导致窗口函数结果不稳定日期格式不统一直接DATE()截断之后格式对不上过滤条件放在WHERE还是HAVING的区别没搞清楚JOIN时没有考虑一对多关联导致的数据膨胀金额字段没有做空值处理或类型转换环比计算时除数为零或NULL没有规避这些细节平时写SQL时可能注意不到因为线上环境的数据相对规范但笔试题目往往故意在这些位置设置陷阱。建议备考时每写完一条SQL都问自己一句如果同一用户有多条记录怎么办如果这个字段为NULL怎么办如果日期跨年怎么办这几种情况都考虑到位了SQL题基本稳了。4. 算法编程题复盘两道经典题型与边界条件算法题一共两道一道偏简单一道中等整体难度低于后端开发岗更贴近LeetCode简单到中等水平。4.1 题目一字符串压缩题目大意是给定一个字符串把连续相同的字符压缩成字符出现次数的形式比如aabcccccaaa压缩成a2b1c5a3。如果压缩后的字符串长度不小于原串则返回原串。这道题的核心是双指针/单次遍历。注意最后一个连续字符段在循环结束后要单独处理public String compressString(String S) { if (S null || S.length() 2) { return S; } StringBuilder sb new StringBuilder(); int count 1; for (int i 1; i S.length(); i) { if (S.charAt(i) S.charAt(i - 1)) { count; } else { sb.append(S.charAt(i - 1)).append(count); count 1; } } sb.append(S.charAt(S.length() - 1)).append(count); String compressed sb.toString(); return compressed.length() S.length() ? compressed : S; }这道题的考察点不是算法有多难而是是否考虑到了边界条件空字符串、单个字符、压缩后和原串一样长此时返回原串。我在实现时一开始没有加最后一段的追加逻辑检查时才发现漏了这个错误很典型。4.2 题目二数组中的第K大元素变体第二道题类似找数组中第K大的元素但加了限制不能使用排序尽量降低时间复杂度。这道题我在LeetCode上刷过原题用快速选择QuickSelect或者大小顶堆都能解决。笔试环境用的是牛客网平台Java代码需要自己写完整不能只写核心函数。我选择的是小顶堆解法时间复杂度O(n log k)空间复杂度O(k)写起来最快也最稳妥public int findKthLargest(int[] nums, int k) { PriorityQueueInteger minHeap new PriorityQueue(k); for (int num : nums) { if (minHeap.size() k) { minHeap.offer(num); } else if (num minHeap.peek()) { minHeap.poll(); minHeap.offer(num); } } return minHeap.peek(); }用堆的解法的好处是思路清晰、不容易写错在笔试时间紧的情况下是最优选择。但如果你追求的是O(n)平均时间复杂度可以用快速选择。快速选择的实现细节更多特别是partition交换逻辑笔试里一旦写错很难调试。所以如果没有十足的把握用堆更稳。经验数据工程岗的算法题整体难度不高不需要刷到LeetCode Hard级别。把Easy和Medium中常见的数组、字符串、链表、哈希表、二叉树、堆的题目刷明白基本够用。相比难度更关键的是正确性和细节处理能力。4.3 笔试平台和IDE的注意点这里多聊几句笔试平台的细节。牛客网的Java环境默认是JDK 8PriorityQueue用法没有问题。但要注意输入输出格式通常不能像本地IDE那样自由调试需要严格按照题目给的输入格式写Scanner解析。编程题提交时不会自动包含import语句PriorityQueue、HashMap这些工具类要记得手动import。我在练习时就遇到过因为漏写import导致编译错误的情况虽然笔试平台上有些自动补全功能但依赖自动补全的风险太大。建议平时就用一个和笔试平台环境接近的在线OJ练习比如牛客网本身。5. 大数据组件理论题的高频考点不只是背概念客观题里的大数据组件考点看起来是背概念但实际上考的是能不能说清楚这个机制解决什么问题、怎么做、有什么代价。只是背结论的话多选题一变形就容易错。5.1 Hadoop HDFS与MapReduce考点HDFS相关的高频考点包括NameNode负责元数据管理、DataNode负责数据块存储、数据块默认大小2.x之后是128MB、副本因子默认3、写入流程中Client需要和NameNode通信获取DataNode列表、读取流程中Client直连DataNode获取数据。MapReduce相关的高频考点包括Shuffle阶段的排序机制、Combiner的适用条件必须满足交换律和结合律、Reducer数量的设置原则。关于这个我有一个记忆技巧把Shuffle过程理解成快递分拣——Map阶段是各家快递收货分区是按城市分类排序是同一个城市内部按街道排好序Reduce阶段是每个城市站点各自处理自己那批快递。用这个类比去理解比死记硬背强得多。5.2 Spark核心机制考点Spark和MapReduce的对比是必考点。Spark为什么快内存计算 DAG优化 Task级别的并行调度。需要理解RDD的窄依赖和宽依赖以及宽依赖为什么会产生Shuffle。有一道单选题考的是以下哪种操作会产生Shuffle选项包括map、filter、groupByKey、mapValues。答案是groupByKey因为reduceByKey和groupByKey都会产生Shuffle而map和filter是窄依赖父子RDD的Partition之间是一对一关系。这个知识点如果只是背groupByKey会产生Shuffle没有理解依赖关系对多选变形题就会发怵。关于Spark运行模式Standalone、YARN、Mesos、Kubernetes的区别也是常考点。笔试中考得最多的就是YARN模式下的Cluster和Client两种部署模式的区别Client模式下Driver运行在客户端进程中Cluster模式下Driver由ApplicationMaster承载。直观记忆方式Client模式适合调试能看到日志Cluster模式适合生产环境客户端可以立即返回。5.3 Kafka与Flink的实时链路考点腾讯音乐的业务特性决定了数据工程团队对实时计算链路要求很高所以Kafka和Flink在笔试中的出现频率不低。Kafka三大语义是高频考点At-most-once消息可能丢、At-least-once消息可能重复、Exactly-once恰好一次。生产环境中最常用的是At-least-once语义配合消费端的幂等处理来达到事实上不重复的效果。Kafka在0.11版本后支持幂等生产者配合事务API可以实现端到端的Exactly-once。这个表述的细节经常出现在多选题里。Flink相关的考点集中在Checkpoint机制和窗口类型。关于Checkpoint和两阶段提交的关系我建议用一个生活化类比来理解Flink就像一家餐厅的店长每做一批菜就拍一张照片记录当前状态Checkpoint如果某道菜做砸了需要重做可以从最近一张照片恢复状态而不是从开店那一刻从头来过。5.4 客观题备考资料与刷题方法大数据组件的理论题我刷了两类资料一类是各家公司的历届笔试真题另一类是自己整理的高频考点清单。笔试前一周开始集中刷客观题每天做一到两套把错题涉及的知识点记到笔记本上。整理知识点的时候我的方法是把关联考点串在一起。比如Kafka的Exactly-once我会同时关联到Flink的Checkpoint、两阶段提交、事务消息、幂等消费者这样考到任何一个方向都能快速联想起来。这个关联记忆法在时间紧、内容多的笔试备考阶段尤其有效。6. 备考路径复盘从时间安排到资料选择的取舍春招笔试的准备和日常学习最大的区别在于有明确的时间窗口。每个人情况不同但我的复盘路径应该对有类似基础的人有参考价值。6.1 我的复习时间线与阶段重点整个备考周期大约三周分三个阶段第一周以SQL为主。每天花2-3小时刷SQL题集中刷窗口函数、连续问题、留存率、复购率、TopN这类必考题。练习题量每天5-8道重点是做一道吃透一道不追求数量。第二周以大数据组件理论为主。这周每天刷Hadoop、Spark、Hive、Kafka、Flink的客观题同时整理错题笔记。这周还穿插做2-3套往年的数据工程岗笔试真题用来检验整体水平。第三周以算法和整套模拟为主。算法每天刷3-5道LeetCode Medium题目优先刷数组、字符串、链表、哈希、堆这几个方向。同时每两天完整模拟一场笔试严格按照120分钟的时间限制。6.2 值得投入时间的资料清单我个人用下来觉得值得投入时间的有这么几个方向SQL练习LeetCode上的SQL题目免费题足够以Hard难度的窗口函数题和连续问题为重点算法练习LeetCode热题100中的Easy和Medium题目覆盖各常见数据结构大数据理论网上能找到的高频面试题汇总注意选择带解析和原理说明的版本真题模拟牛客网上历年的数据工程、大数据开发笔试题目尽量找带答案的值得一提的是很多人在准备时容易陷入一个误区把大量时间花在复习MapReduce的源码级别细节上实际上笔试考的是应用层面的原理理解。MapReduce的Shuffle细节会考但不会考到每个排序算法的底层实现把精力花在更常考的Spark、Flink上性价比更高。6.3 复习过程中踩过的几个坑第一个坑是只刷题不复盘。春招笔试准备很容易陷入题海战术的舒适区做完对答案就完事。但笔试真题的题目量有限不复盘的话做过的题过几天又忘了。第二个坑是忽略了牛客网笔试平台的输入输出格式。前几次在本地IDE写好的代码到牛客网上提交时因为Scanner处理问题导致运行超时或者编译失败。后来我养成了习惯练习时直接在牛客网的编辑器里写熟悉它的补全机制和报错提示。第三个坑是算法题不写注释。笔试判卷时虽然不看你写了什么注释但人检查时会看——而且更关键的是你自己在调试过程中注释能帮你理清思路。时间紧张的时候有注释的代码改动起来省力得多。6.4 笔试后的复盘无论结果如何都要做考完笔试后的两三天我重新把整场笔试的题目回忆了一遍把答得不顺的题都重新做了一遍。这个过程很痛苦因为看到错题会想起笔试时的场景但恰恰是这种复盘最有价值。笔试不仅仅是一场考试它更像是对你当前技术栈的一次全面体检。我在复盘中发现SQL的连续问题虽然会做但不够熟练遇到变体就反应变慢Flink的State相关机制理解不够深入。这两个短板如果不去补就算这场笔试侥幸过了面试时也大概率会暴露。所以我的建议是每一场笔试结束后给自己做一个知识漏洞清单把暴露出来的问题写下来在接下来的备考中有针对性地补。笔试和面试本身是连续的今天的笔试漏洞往往就是明天的面试考题。最后回顾整场腾讯音乐数据工程岗第二批笔试时间120分钟题量适中难度中等SQL占比高大数据组件理论覆盖面广算法难度不大。核心考察的是基本功——SQL的扎实程度、大数据组件原理理解的深度、编程实现的正确性。如果你正在备考类似岗位我的建议很简单SQL窗口函数练到条件反射大数据组件重点理清Spark和Flink的执行原理算法保持每天手写代码的手感再完成两三套真题模拟基本就具备了通过笔试所需的能力储备。