数据开发每日面试题 Day 5

1|真实面经:Spark 参数怎么调?

来源:近期公开面经|字节跳动|数据开发与数据分析岗|面试时间 2026-03-31|难度:★★★★☆

牛客近期收录的这场面试明确记录了"Spark 参数怎么调",随后继续追问 Hive、Spark、数据湖等分布式架构共有的性能瓶颈。

查看牛客大数据开发面经合集

核心考察点

面试官不是想听你背:

sql 复制代码
executor-memory = 8G
executor-cores = 4

而是在看:

你是否会根据任务现象判断资源瓶颈。

标准回答

我会先判断瓶颈属于:

sql 复制代码
CPU
Memory
Shuffle
GC
数据倾斜
IO
并行度

而不是直接修改参数。

例如任务大量:

sql 复制代码
GC
Executor Lost
OOM

重点看:

spark.executor.memory

spark.executor.memoryOverhead

executor cores

缓存数据量

单 Task 数据量

如果 CPU 利用率低、Task 数又很少:

可能是并行度不足。

可以检查:

sql 复制代码
spark.sql.shuffle.partitions

以及输入分区数。

如果 Task 数特别多、每个 Task 数据很小:

反而可能调度开销过大。

如果 Shuffle 特别大:

参数不是第一解决方案,应该先检查 Join、聚合、分区和数据倾斜。

面试口述

Spark 调优我一般不会从某个固定参数开始,而是先通过 Spark UI 判断瓶颈属于 CPU、内存、Shuffle、GC、数据倾斜还是并行度,再针对性调整 Executor 资源和 Shuffle Partition。比如大量 OOM 时我会检查单 Task 数据量、缓存和 Memory Overhead;如果大量小 Task,则减少不必要的分区;如果 Shuffle 特别大,我会优先优化执行逻辑而不是单纯增加资源。

追问

Executor Core 是不是越多越好?

sql 复制代码
不是。单 Executor Core 太多意味着更多 Task 共用一个 JVM:
sql 复制代码
GC压力
内存竞争
单Executor故障影响范围

都会增加。

2|SQL:找出连续登录 ≥ 3 天的用户

来源:自拟高频题|难度:★★★★☆

连续登录是今年公开 SQL 面经整理中仍反复出现的题型。

表:

sql 复制代码
login_record(
    user_id,
    login_date
)

核心思路

非常经典:

sql 复制代码
日期 - row_number。

先去重:

sql 复制代码
WITH t AS (
    SELECT DISTINCT user_id, login_date
    FROM login_record
),
t2 AS (
    SELECT
        user_id,
        login_date,
        ROW_NUMBER() OVER(
            PARTITION BY user_id
            ORDER BY login_date
        ) AS rn
    FROM t
),
t3 AS (
    SELECT
        user_id,
        login_date,
        DATE_SUB(login_date, INTERVAL rn DAY) AS grp
    FROM t2
)
SELECT
    user_id,
    MIN(login_date) AS start_date,
    MAX(login_date) AS end_date,
    COUNT(*) AS consecutive_days
FROM t3
GROUP BY user_id, grp
HAVING COUNT(*) >= 3;

为什么 date - rn 能分组?

连续:

sql 复制代码
date        rn

09-01       1
09-02       2
09-03       3

分别减:

sql 复制代码
09-01 - 1
09-02 - 2
09-03 - 3

得到相同日期。

所以连续区间天然形成同一组。

追问

同一天登录十次怎么办?

必须先:

sql 复制代码
DISTINCT user_id, login_date

否则会破坏 row_number。

3|MySQL:覆盖索引是什么?为什么能减少回表?

来源:自拟高频题|难度:★★★☆☆

假设:

sql 复制代码
CREATE INDEX idx_user_time
ON orders(user_id, create_time);

查询:

sql 复制代码
SELECT user_id, create_time
FROM orders
WHERE user_id = 1001;

需要的数据:

sql 复制代码
user_id
create_time

都已经存在于索引中。

因此:

可以直接从索引得到结果,而不必再通过主键访问聚簇索引取得整行。

这就是:

覆盖索引。

什么叫回表?

InnoDB 二级索引叶子节点通常保存:

sql 复制代码
索引列
+
主键值

如果:

sql 复制代码
SELECT user_id, create_time, amount

但 amount 不在这个二级索引里,就可能:

sql 复制代码
二级索引
↓
取得主键
↓
聚簇索引
↓
取得 amount

这就是回表。

追问

是不是 SELECT 字段越少越好?

从 IO 和覆盖索引角度通常有帮助,所以避免无意义 SELECT * 是好习惯。

但:

不能为了覆盖索引无限往索引里塞字段。

因为索引本身也有存储和写入维护成本。

4|数仓:维度退化是什么?订单号为什么可能直接放事实表?

来源:自拟高频题|难度:★★★☆☆

事实表:

sql 复制代码
order_fact

可能包含:

sql 复制代码
order_id
user_key
product_key
date_key
amount

其中:

sql 复制代码
user_key → 用户维表
product_key → 商品维表

但 order_id 呢?

如果订单号:

sql 复制代码
没有大量需要单独维护的描述属性
主要用于事实查询和关联

没必要建立:

sql 复制代码
dim_order

然后里面只有:

sql 复制代码
order_id

这种意义很弱的维表。

于是直接把业务维度标识:

sql 复制代码
order_id

保留在事实表中。

这就是:

sql 复制代码
Degenerate Dimension,退化维度。

常见例子

sql 复制代码
订单号
发票号
交易流水号

追问

退化维度是不是事实?

不是。

订单号本身不是:

sql 复制代码
可加总的度量

它仍然是维度性质,只是:

没有独立维表。

5|MapReduce:Combiner 为什么不能随便用?

来源:自拟高频题|难度:★★★★☆

Map 输出:

sql 复制代码
key → value

通常需要经过网络:

sql 复制代码
Shuffle

发送到 Reducer。

Combiner 可以在 Map 端先做:

sql 复制代码
局部聚合。

例如 WordCount:

sql 复制代码
apple 1
apple 1
apple 1

先变成:

sql 复制代码
apple 3

再传输。

这样明显减少 Shuffle。

但是为什么不能随便用?

因为 Combiner:

可能执行,也可能不执行,也可能执行多次。

所以业务逻辑必须满足:

局部聚合不会改变最终结果。

例如:

sql 复制代码
SUM
MAX
MIN

通常容易满足。

但是平均值:

sql 复制代码
AVG

不能简单:

sql 复制代码
局部平均
↓
再平均

例如:

sql 复制代码
组A:[1, 1]
平均 = 1

组B:[100]
平均 = 100

平均两个局部平均:

sql 复制代码
(1 + 100) / 2 = 50.5

真实平均:

sql 复制代码
102 / 3 = 34

错误。

正确做法可以传:

sql 复制代码
(sum, count)

最后:

sql 复制代码
total_sum / total_count

一句话

Combiner 是优化,不应该成为结果正确性的必要条件。

这句话值得背。

6|Hive:count(distinct user_id) 数据量巨大时为什么可能慢?

来源:自拟高频题|难度:★★★★☆

核心问题:

去重需要让相同 user_id 汇聚到一起。

数据规模大时可能产生:

sql 复制代码
大量 Shuffle
网络 IO
Reducer 压力
热点 Key

尤其如果执行计划形成:

sql 复制代码
单阶段重聚合

瓶颈可能非常明显。

怎么优化?

根据场景可以:

sql 复制代码
先局部去重再全局统计
分组两阶段聚合
合理增加并行度
利用 Bitmap / HLL 等近似去重
预聚合

例如允许近似 UV 时:

HyperLogLog 往往比精确 distinct 更省空间。

追问

为什么不能永远用 HLL?

因为它是:

近似算法。

如果银行对账要求:

sql 复制代码
精确人数 = 1,000,000

就不能随便接受概率误差。

7|Flink:Checkpoint 和 Savepoint 有什么区别?

来源:自拟高频题|难度:★★★★☆

两者都可以保存状态,但用途不同。

Checkpoint

主要用于:

自动故障恢复。

由 Flink 周期性触发:

sql 复制代码
Job运行
↓
Checkpoint
↓
Checkpoint
↓
Checkpoint

Job 崩溃:

从最近成功的 Checkpoint 恢复。

生命周期更偏系统自动管理。

Savepoint

主要用于:

人工运维和版本迁移。

例如:

sql 复制代码
停止旧Job
↓
创建Savepoint
↓
修改代码
↓
从Savepoint启动新Job

适合:

sql 复制代码
升级
迁移
修改并行度
计划性停止

一句话

sql 复制代码
Checkpoint → 故障恢复
Savepoint  → 运维迁移

但底层都涉及:

Stateful computation snapshot。

追问

有 Checkpoint 就一定 Exactly-Once 吗?

不一定。

端到端 Exactly-Once 还要求:

sql 复制代码
Source
State
Sink

整体配合。

如果 Sink:

sql 复制代码
每次恢复后重复 INSERT

照样可能重复。

8|Kafka:为什么 Kafka 吞吐量这么高?

来源:自拟高频题|难度:★★★★☆

别只回答:

因为用了磁盘顺序写。

至少讲四层。

① 顺序写

Kafka 日志是:

sql 复制代码
Append Only

顺序追加。

磁盘顺序 IO 比随机 IO 高效很多。

② Page Cache

Kafka 大量利用操作系统:

sql 复制代码
Page Cache

减少 JVM 内存管理压力。

③ Zero Copy

发送数据时尽量减少:

sql 复制代码
Kernel
User Space
Kernel

之间不必要的数据复制。

④ Batch

Producer 可以批量发送:

sql 复制代码
message
message
message
↓
batch

减少:

sql 复制代码
网络请求
系统调用

⑤ Partition 并行

多个 Partition:

可以由多个 Broker / Consumer 并行处理。

面试口述

Kafka 高吞吐并不是单一机制,而是顺序追加日志、Page Cache、批处理、减少数据复制以及 Partition 并行共同作用的结果。

9|Redis:RDB 和 AOF 怎么选?

来源:自拟高频题|难度:★★★★☆

RDB

周期性生成:
某一时刻的数据快照。

优点:

sql 复制代码
文件紧凑
恢复速度较快
适合备份

风险:

两次快照之间宕机可能丢失一段数据。

AOF

记录:

数据修改操作。

例如:

sql 复制代码
SET
INCR
DEL

可以配置不同刷盘策略。

通常:

数据持久性可以比低频 RDB 更强。

但文件和写入开销通常更高,因此存在:

sql 复制代码
AOF Rewrite

等机制。

面试不要回答

RDB 快,AOF 安全,所以生产一定用 AOF。

真实生产会结合:

swift 复制代码
恢复速度
可接受数据丢失窗口
性能
备份
Redis版本
高可用架构

综合决定。

近期 2026 面经整理里,Redis 持久化已经出现从"RDB/AOF 是什么"继续追到混合持久化、宕机后可能损失多少数据的趋势。

10|Linux:CPU 100%,你怎么定位?

来源:自拟场景题|难度:★★★★☆

不要第一句话:

重启服务器。

先:

sql 复制代码
top

看:

sql 复制代码
load average
CPU user/system/iowait
哪个进程占CPU

假设 PID:

sql 复制代码
12345

进一步:

sql 复制代码
top -H -p 12345

看:

哪个线程占 CPU。

还可以结合:

sql 复制代码
ps
pidstat
vmstat
iostat

判断究竟是:

sql 复制代码
CPU计算
IO等待
频繁上下文切换

如果是数据任务

再回到:

sql 复制代码
Spark/Flink Task
数据倾斜
序列化
死循环
GC
并行度

排查。

一个重要区别

sql 复制代码
CPU 100%

不一定意味着:

CPU 是问题。

例如大量 IO wait 时,系统表现慢但根因可能是磁盘。

所以一定看:

sql 复制代码
us
sy
wa

等指标。

11|Doris / ClickHouse:为什么 OLAP 场景常使用预聚合?

来源:自拟高频题|难度:★★★☆☆

假设明细:

sql 复制代码
每天 10 亿条交易

领导每天查询:

sql 复制代码
SELECT province, SUM(amount)
FROM transactions
WHERE dt = ...
GROUP BY province;

每次扫描十亿条显然昂贵。

可以提前形成:

sql 复制代码
province_daily_sales

例如:

sql 复制代码
Beijing | 2026-09-08 | 10亿
Shanghai| 2026-09-08 | 8亿

查询直接:

sql 复制代码
几百行

而不是十亿行。

这就是预聚合价值:
用存储和预计算换查询延迟。

但是为什么不能所有维度组合全部预聚合?

如果有:

sql 复制代码
province
city
age
gender
channel
product
...

所有组合会产生:

维度组合爆炸。

所以需要根据:

sql 复制代码
查询频率
业务指标
实时性
存储成本

选择聚合粒度。

12|结合你的项目:MySQL CDC 为什么比"每分钟 SELECT 一次"更适合实时链路?

来源:针对项目设计|难度:★★★★☆

假设不用 CDC。

Python 每分钟:

sql 复制代码
SELECT *
FROM orders
WHERE update_time > last_time;

看起来也能做增量。

但存在几个问题。

① 时间边界

例如:

sql 复制代码
last_time = 12:00:00

同一毫秒多条更新、事务提交顺序和时间精度处理不好,就可能:

sql 复制代码
漏
或
重复

② 数据库压力

每分钟扫描:

sql 复制代码
update_time > ?

意味着持续查询业务数据库。

CDC 则利用:

数据库已有的变更日志,例如 MySQL Binlog。

③ Delete

轮询表:

sql 复制代码
SELECT ...

很难自然知道:

哪条数据刚被 DELETE。

CDC 日志可以表达:

sql 复制代码
INSERT
UPDATE
DELETE

④ 低延迟

轮询天然存在:

sql 复制代码
poll interval

CDC 可以更接近实时。

⑤ 顺序和位置

CDC 可以维护:

sql 复制代码
Binlog File
Position
GTID

等进度。

因此更容易:

断点恢复。

追问
那 CDC 就绝对不会丢数据?

不能这么说。

还要考虑:

sql 复制代码
Connector状态
Checkpoint
Offset
Binlog保留时间
Schema变化
Sink语义

所以 CDC 只是提供了更可靠的变更捕获基础。

13|场景题:银行 ODS → DWD 跑完了,但数据量比昨天突然少 40%,你发布吗?

来源:针对银行数仓场景设计|难度:★★★★★

答案首先是:

不能因为任务状态 SUCCESS 就直接发布。

调度成功只代表:

程序正常结束

不代表:

数据正确

第一步:判断是否业务真实变化

比较:

sql 复制代码
今天记录数
昨天记录数
过去7/30天基线
上游源表记录数

如果昨天:

sql 复制代码
1亿

今天:

sql 复制代码
6000万

需要判断:

sql 复制代码
节假日?
业务停机?
源系统切换?
部分机构没有上数?

第二步:分层对账

例如:

sql 复制代码
源系统 1亿
↓
ODS 6000万

问题:

入仓。

如果:

sql 复制代码
源系统 1亿
ODS    1亿
DWD    6000万

问题:

ODS → DWD。

继续按照:

sql 复制代码
机构
日期
业务类型
分区

拆分。

例如发现:

sql 复制代码
北京 100%
上海 100%
广东 0%

那问题瞬间从:

"少了 4000 万"

缩小成:

"广东分支数据没到。"

第三步:检查规则变化

尤其:

sql 复制代码
WHERE条件
Join
Inner Join
字典映射
NULL
去重

例如:

sql 复制代码
FROM transaction t
INNER JOIN dim_branch b
ON t.branch_code = b.branch_code

如果维表突然缺失大量 branch:

Inner Join 会把事实数据直接过滤掉。

第四步:阻断下游

如果数据异常:

sql 复制代码
DWD
✕
DWS
✕
ADS
✕
驾驶舱

不要让错误数据继续传播。

第五步:修复 + 补数

修复后:

sql 复制代码
指定 biz_date
↓
重跑异常分区
↓
数据量检查
↓
金额/笔数对账
↓
关键指标检查
↓
恢复下游

面试口述

我不会把任务成功等同于数据成功。出现 40% 的异常下降时,我会先判断是否存在真实业务原因,然后从源系统、ODS、DWD 逐层做数量和关键指标对账,并按机构、业务类型等维度拆分来定位第一个发生差异的位置。同时阻断依赖该数据的下游任务。修复后针对受影响业务日期和分区补跑,并完成数量、金额及核心指标校验后再恢复发布。

sql 复制代码
银行数仓经验
+
DolphinScheduler
+
数据质量
+
补数
+
生产责任
相关推荐
llilian_161 小时前
PTP时钟服务器时间溢出隐患解决方案 1588时钟服务器 ptp服务器
大数据·网络·单片机·嵌入式硬件·51单片机
Elastic 中国社区官方博客1 小时前
将 Vercel 数据导入 Elastic:无需安装任何东西的无服务器可观测性
大数据·运维·elasticsearch·搜索引擎·云原生·serverless·全文检索
cspttty1 小时前
数字营销应届岗技能栈:Excel、SQL、GA4、投放平台与AI工具怎么学
大数据
AgentMaster1 小时前
智能外呼系统技术实战:语音 AI、线路集成与成本优化的完整指南
大数据
故七月2 小时前
大模型 RAG 检索下的信源优化:如何提升企业信息在 AI 问答中的采信概率
大数据·geo·#rag #大模型检索·#实体对齐
DBA_G2 小时前
GBase 8a数据库执行计划查看方式解析
数据库
润乾软件2 小时前
SQLazy: 按订单 SKU 条件分配仓库
sql·sqlazy
初願致夕霞2 小时前
MySQL_事务(MVCC机制详解)
数据库·mysql
geovindu2 小时前
sql: Data Modeling Patterns using mysql
sql·mysql·设计模式·数据库开发