2025携程数据开发笔试复盘:SQL、大数据组件与数仓建模全解析
2025年春招刚拉开帷幕我就扎进了携程集团数据开发工程师的第一批笔试。作为一个盯了大厂数据岗大半年的人说实话打开笔试链接前心里还是有点打鼓的。但真正把卷子做完、复盘完我发现这次笔试的考察逻辑其实非常清晰它不考偏题怪题而是把数据开发工程师日常工作中最高频、最容易踩坑的能力点用一套题完整地串了起来。这篇文章我打算从笔试的整体布局、SQL重头戏、大数据组件原理、数仓建模与主观题、以及我踩过的坑这几个维度做一个完整复盘。不管是准备春招秋招的在校生还是想转岗大数据开发的朋友这篇内容应该能帮你看清楚大厂数据开发笔试到底在考什么以及怎么准备才不掉进坑里。1. 笔试开局这批题的整体画风与考察逻辑1.1 2025年春招数据开发岗的大背景先说个背景。2025年春招的数据开发岗位体感上比前两年要热不少。原因也不复杂大模型带火的数据应用、各家公司都在做数据资产盘点和实时数仓升级导致数据开发的需求从过去的“离线报表加工”逐步变成了“离在线一体、数据服务化”。这意味着笔试考察的维度更宽了过去只要会写SQL就能过初筛的时代早就过去了。我翻了一下身边同学收到的笔试通知今年携程的数据开发笔试时间给得比较宽裕我记得是120分钟题量不算特别大但坑不少。这种设置其实很有讲究——它不希望你靠“手速”蒙混过关而是考验你在有限时间内对问题的拆解和取舍能力。1.2 题型构成与时间安排复盘我拿到的这套卷子后续根据多位参加同一批次笔试的同学反馈题型基本一致大致分四块题型题量建议用时核心考察点单选题15题左右25分钟大数据组件原理、操作系统/网络基础、Java/Python基础多选题5题左右10分钟容易混淆的原理性知识多选少选都扣分SQL编程题4题左右60分钟窗口函数、业务统计、复杂关联、数据质量处理主观问答题2题25分钟数仓建模、数据倾斜解决思路选择题和问答题属于“会就会不会就蒙”的类型真正的拉分项在SQL编程题。这也是我后面要花大篇幅讲SQL的原因——数据开发笔试里SQL的权重往往比很多人想象得大得多因为它直接反映了一个人对业务数据的理解深度。1.3 第一印象这套题在“筛选什么人”做完题之后我有一个非常强烈的感受这套题不是在招“只会写SQL的工具人”而是在招“能理解业务、能设计数据链路、能排查数据问题”的工程师。比如选择题里考了HDFS写入流程中副本的管道写入顺序这题如果只是背过“副本数是3”是不够的你得知道客户端先写第一个DataNode再由第一个DataNode转发给第二个这样形成管道才能答对。再比如SQL题里有一道关于订单复购的统计它表面考SQL实际上考你“订单表和支付表一对多关系下如何去重”这是真实业务里天天会遇到的问题。所以准备笔试的时候不要只看面经背答案一定要理解背后的原理和业务含义。2. 重头戏SQL题型拆解与业务场景还原2.1 窗口函数排名类题目的通用解法携程的SQL题里窗口函数是绝对主角。我记得第一道SQL题大概是这个场景给定酒店订单表包含酒店ID、订单ID、用户ID、订单金额、下单时间要求统计每个酒店下订单金额排名前10的订单。这种题如果不会窗口函数用普通GROUP BY加子查询也能做但写出来的SQL会又臭又长而且很容易漏边界条件。窗口函数解法大概是这样SELECT hotel_id, order_id, user_id, order_amount, order_time, rank_num FROM ( SELECT hotel_id, order_id, user_id, order_amount, order_time, ROW_NUMBER() OVER (PARTITION BY hotel_id ORDER BY order_amount DESC, order_time ASC) AS rank_num FROM hotel_order WHERE order_status paid ) t WHERE rank_num 10这里有几个关键点PARTITION BY hotel_id是按酒店分组这是“每个酒店”这个语义的直接映射。ORDER BY order_amount DESC是排名依据但要注意如果金额相同需要决定是否并列。窗口函数里ROW_NUMBER()会给并列的订单随机排先后RANK()和DENSE_RANK()才会给并列的订单相同名次。题目如果要求“前10名且金额相同算并列”那就要用DENSE_RANK()否则用ROW_NUMBER()就够了。外层套一层子查询再过滤rank_num 10是因为窗口函数不能直接用在WHERE子句里。这个点很多新手会踩。我自己的习惯是拿到SQL题先圈出三个东西分组维度每个XX、排序字段按什么排、过滤条件只要什么样的数据。把这三件事在草稿纸上写清楚再动笔写SQL正确率会高很多。2.2 经典业务统计留存、复购、连续登录第二个高频类型是业务指标计算。这种题在携程这类OTA公司尤其常见因为订单、用户、行程天然适合出这类题目。有一个我印象很深的题给定用户登录日志表包含用户ID和登录日期要求统计连续7天都有登录行为的用户。经典的解法是利用date_sub和row_number的组合SELECT DISTINCT user_id FROM ( SELECT user_id, login_date, date_sub(login_date, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date)) AS date_group FROM ( SELECT DISTINCT user_id, login_date FROM user_login_log ) t1 ) t2 GROUP BY user_id, date_group HAVING COUNT(1) 7这里有几个隐藏的坑内层要先对user_id, login_date去重不然同一个用户一天登录多次会被当成多条记录导致连续天数被放大。要按用户分组后对日期排序再计算date_sub(login_date, 序号)如果日期是连续的这个差值会保持不变一旦日期中断差值就会变化。最后GROUP BY user_id, date_group后统计数量如果大于等于7说明这个用户有一个连续7天的登录区间。我为什么说这种题是“送分题里的送命题”因为思路大家都会但边界条件很容易出错。比如登录日期跨月、跨年时date_sub和日期格式的处理就很重要如果源表里日期是yyyyMMdd这种字符串而不是日期类型你得先CAST或者用from_unixtime转成标准日期再计算。2.3 复杂关联与数据质量校验类题目除了窗口函数今年的笔试题里还出现了一些“非典型”SQL题考的是数据质量校验。大概场景是有一个订单事实表和一个订单明细表需要按照订单ID关联但两个表都存在重复记录要求写出SQL校验关联后数据是否一致、是否存在一对多或多对多关联。这种题很容易让人懵因为平时刷题很少遇到。但真实工作中数据质量校验是数据开发每天都要做的事。我的解法思路分三步第一步分别统计两张表的订单ID去重数、总行数对比是否一致。第二步用订单ID关联后统计数据是否膨胀判断是否存在一对多关联。第三步用FULL OUTER JOIN找出两张表互相关联不上的订单ID定位数据缺口。SELECT COALESCE(a.order_id, b.order_id) AS order_id, CASE WHEN a.order_id IS NULL THEN only_in_detail WHEN b.order_id IS NULL THEN only_in_fact ELSE matched END AS match_status FROM fact_order a FULL OUTER JOIN detail_order b ON a.order_id b.order_id WHERE a.order_id IS NULL OR b.order_id IS NULL这类题考察的不只是SQL语法而是“你是否具备数据质量意识”——能不能想到数据对不上时该怎么排查、从哪个维度切入。如果你平时就养成了写数仓任务时做数据校验的习惯遇到这种题会非常轻松。3. 大数据组件从Hive到Flink的考察逻辑3.1 Hive与Spark SQL优化题背后的原理选择题部分有相当比例是Hive和Spark SQL的优化题。比如有一道题是问“以下哪种方式能有效解决Hive小文件过多的问题”。选项里给了CombineHiveInputFormat、MERGE small files、repartition、调整分区数等。这种题光背答案是没用的你得理解小文件的产生链路。Hive小文件过多的根本原因通常是上游任务生成了大量低数据量的文件比如Spark的repartition(1000)但实际数据量很小或者流式任务每两分钟落一次盘。小文件多了之后NameNode元数据压力变大查询时要打开的文件数变多任务执行效率自然下降。解决思路是分层的如果小文件已经产生可以在查询前用CombineHiveInputFormat合并输入或者用INSERT OVERWRITE ... SELECT ... DISTRIBUTE BY ...重新写入把数据按某个键重新分布。如果要从源头避免就需要控制Spark任务的输出文件数合理设置spark.sql.shuffle.partitions或者在流式任务里做窗口攒批。笔试里考这种题本质上想确认你在真实项目中到底有没有遇到过、处理过小文件问题而不只是停留在概念层面。3.2 Flink与实时计算数据开发的新常态今年携程的笔试题里Flink相关内容明显比往年多。这符合行业趋势现在做数据开发纯离线已经不够看了很多业务场景要求实时指标。有一道多选题是关于Flink的checkpoint机制选项包括checkpoint的存储位置、exactly-once如何实现、barrier对齐的作用、checkpoint失败后任务是否自动恢复。这题如果对Flink原理理解不深很容易选错。我的理解是Flink的checkpoint核心逻辑是把状态和算子位置定期持久化。它通过barrier机制来实现精确一次语义——上游算子收到所有输入流的barrier后把当前状态做一次快照。这里有个关键点是“barrier对齐”如果配置了exactly-onceFlink会等待所有输入分区的barrier都到达才做快照如果配的是at-least-once则不等待对齐。理解了这套机制选项里的坑基本都能避开。另外还有一道关于水印watermark的题考的是乱序数据和延迟数据怎么处理。这种题在实时数仓场景里很常见——你要确定一个时间窗口的数据什么时候算“齐了”可以触发计算。核心就是watermark的设置不能太保守也不能太激进太保守会导致结果延迟太激进会漏数据。3.3 数据倾斜面试和笔试共同的“高频钉子户”数据倾斜几乎是所有大厂数据岗笔试面试的必考题携程也不例外。这次笔试里数据倾斜以两种形式出现选择题里考概念主观题里考解决思路。数据倾斜的本质是数据分布不均导致某个reduce task处理的数据量远大于其他task。常见场景有两个GROUP BY倾斜某个key的数据量特别大比如城市维度的“上海”占了全国订单的40%按城市分组汇总时上海的reduce节点就会很慢。JOIN倾斜事实表和维度表关联时某个热点key在事实表里出现的次数特别多比如大V用户的订单量巨大。解决思路我在答题时给了一个由浅入深的框架如果只是某个key倾斜可以先看看能不能加随机前缀打散。比如GROUP BY时如果聚合函数是count(distinct)可以先在key后面拼接随机数分两步聚合。如果是JOIN倾斜可以把热点key的数据单独拎出来和维度表广播map join非热点key走正常shuffle join最后用UNION ALL合并。如果倾斜是因为空值造成的可以把空值随机加后缀再分组避免所有空值涌到同一个reducer。这个问题的答法其实很能体现一个数据开发工程师的经验深度——只会说“加盐”是不够的你得能根据不同场景给出对应方案并解释为什么这个方案有效。4. 数仓建模与主观题高分答题思路拆解4.1 维度建模星型模型与雪花模型的取舍主观题里有一道是关于数仓建模的大概问的是“订单分析场景下是选择星型模型还是雪花模型为什么”。我拿到这道题的第一反应是不能只回答“星型模型查询快雪花模型省空间”这太浅了。阅卷人想看到的是你在真实业务约束下的决策能力。我的答题思路是分层的。先给出结论在订单分析这种对查询性能要求较高的场景优先选择星型模型。然后展开理由星型模型把事实表和维度表直接关联查询无需多层嵌套SQL写起来简单执行计划的优化也更容易。雪花模型通过维度表规范化比如把城市维度拆成城市-省份-国家三层虽然减少了数据冗余但查询时关联层级变多性能会受影响。在大多数数仓场景下存储成本远低于计算成本适度冗余换取查询效率是划算的。如果确实存在某些层级维度天然有上下钻取需求比如地域维度的省市县下钻可以在DIM层单独做成多级维度表而不是在指标层强行用雪花模型。4.2 数仓分层设计ODS/DWD/DWS/ADS各自的职责另一道主观题是让设计一个订单数仓的分层架构。这种题没有标准答案但得答出分层的核心思想和每一层的作用。我给出的框架是这样的ODS层操作数据存储层贴源落地保留业务库的原始数据不做过多加工。这里要注意的是ODS层不是简单拷贝而是要加上数据抽取时间、数据来源标识等元信息字段方便追溯和数据质量监控。DWD层明细数据层做清洗、去重、标准化、维度退化。比如把订单状态从数字码翻译成可读文本把各业务线的支付方式统一枚举值。DWD层是后续所有数据的基础这一层质量不行上面全是空中楼阁。DWS层汇总数据层按业务主题做轻度汇总比如按酒店维度、按城市维度、按天汇总订单量、GMV、用户数等。DWS层服务的是日常报表和自助分析不需要每次从明细重新计算。ADS层应用数据层面向具体应用和场景的深度加工比如首页推荐用的用户行为特征表、营销活动用的用户分群表。我当时特意强调了一点分层的最大价值不是“别人都这么分所以我也这么分”而是每层都有明确的职责边界上游出问题不会直接污染下游。这能体现你对数仓设计本质的理解。4.3 程序设计与算法题时间预算内的取舍除了纯数据类的题目笔试里也出现了一些基础编程题。携程的数据开发岗不像后端岗那样考大量Hard级算法但基础的数组、字符串、哈希表、链表操作还是需要掌握的。我遇到的是一道用Java/Python实现的题目大概是需要处理一份订单数据集找出连续下单天数最长的用户输出用户ID和最大连续天数。这种题如果用SQL写很简单但笔试要求你用编程语言实现。这里有一个很重要的策略如果时间紧张可以先用暴力解法两层循环保证通过率再回来优化。笔试的判分通常覆盖部分用例暴力解至少能拿到基础分。我给自己定的规则是一道编程题如果15分钟内想不出最优解就直接上暴力法绝不恋战。另外编程环境里会提供字符串处理和集合操作等常用库务必提前熟悉。我这次笔试用的是在线的JS编辑器不支持本地调试所以代码里每个模块都要自己仔细检查尤其是边界条件空数组、只有一个元素、日期跨月等。5. 踩坑记录与备考清单这些教训希望你不需要经历5.1 我在这批笔试里踩过的三个坑第一个坑是读题太着急。有一道SQL题题目描述了订单表有“取消订单”的状态字段要求在统计时排除。我第一次读题时没注意到这个细节写出来的SQL把所有订单都算进去了后来回头检查才发现漏了过滤条件白白浪费了时间。这里也提醒大家SQL题的WHERE条件往往是最后最容易丢分的地方一定要把题干的每个定语都圈出来。第二个坑是连续登录问题里的日期去重。我一开始以为登录日志表里每个用户每天最多一条记录就没做去重结果算出来的连续天数比实际大。后来发现日志表里同一个用户同一天可能有多条登录记录APP端、Web端、小程序端各一条这种重复如果不去掉整个计算结果就是错的。所以现在我做这类题的第一反应就是“要不要先DISTINCT”。第三个坑是主观题写太满导致时间不够用。我在数仓建模那道题上花的时间明显超标好处是答得比较全面坏处是最后一道编程题只剩20分钟只能匆匆写了个暴力解没时间做优化。后来复盘发现如果当时给主观题设置一个时间硬上限比如25分钟就收手编程题能做得更从容。5.2 数据开发笔试通用备赛路线考完之后我重新捋了一遍数据开发岗的备战重点按照“笔试通过率最高”的原则排了一个优先级第一优先级SQL窗口函数、聚合函数、多表关联。这是笔试的绝对主力LeetCode SQL题、牛客SQL题至少各刷30道。刷的时候不要只求“能运行过”要多想一步“如果数据量翻100倍还会这么写吗”。第二优先级大数据组件原理HDFS、Hive、Spark、Flink、Kafka、HBase。重点掌握读流程、写流程、副本机制、checkpoint、数据倾斜、背压这些高频考点。第三优先级数仓理论维度建模、分层架构、拉链表、缓慢变化维、事实表类型。这部分笔试直接考概念的可能性不大更多是作为主观题的答题素材。第四优先级算法基础数组、链表、哈希、栈队列、基础排序和查找。不用卷Hard题但把常见Medium题刷到能快速写对的程度是有必要的。另外特别建议笔试前花半小时了解一下目标公司的业务线。比如携程的核心业务是酒旅那就要想清楚酒旅数据里订单、支付、退款、点评这些主题之间的关联关系。笔试里很多业务场景题其实就是把公司实际业务简化后搬上来的。5.3 给准备下一批笔试同学的一句话我个人最大的体会是数据开发笔试考的不是“你知道多少技术名词”而是“你能不能把技术用在真实的业务数据上”。这背后的积累不是考前突击三五天就能速成的而是靠平时做项目时多问几个“为什么这样设计”“如果数据异常怎么办”堆出来的。如果你现在已经收到了笔试通知时间不多了那就把SQL窗口函数、数据倾斜、数仓分层这三个方向反复吃透。这三块足够覆盖笔试的大部分分数。如果你还有一两周以上的时间赶紧去把Flink和Spark的核心机制完整过一遍今年这两块的出题比重比往年明显更高。祝各位都能顺利通过笔试拿到心仪的面试机会。如果后续我面完试有时间再回来聊聊面试环节的实战复盘。