当前位置: 首页 > news >正文

大数据数仓面试问题

问题一. 数仓为什么要分层,数仓分层的好处,分层的作用

💡 分层的核心思想就是解耦,再解耦,把复杂的问题简单化。

💡 分层本质:通过牺牲短期开发成本(20%-30%额外建模工作),换取系统长期演进能力。

数仓分层是大数据架构设计的核心理念之一,其优势体现在以下几个方面(按优先级排列):

1. 数据结构化治理(核心价值)

  1. 逐层抽象:通过ODS→DWD→DWS→ADS分层模型,实现原始数据→明细数据→聚合数据→应用数据的渐进加工。将复杂问题简单化。将一个复杂的业务加工逻辑拆解成多个步骤来分步完成,每一层只聚焦于某一类问题。当数据出现问题时,通过追溯可以很快定位到问题出现在哪一层,并且只需要对这一层逻辑修复即可。
  2. 质量管控:在DWD层统一实施字段标准/空值处理/数据稽核,避免下游污染(例:手机号格式统一为+86-138****1234)
  3. 血缘可溯:分层后可通过元数据工具(如Atlas)清晰跟踪指标口径的完整加工路径

2. 计算资源复用(成本优化)

  1. 中间沉淀:DWS层预存共性维度聚合结果(如日粒度UV、GMV),避免多个业务方重复计算原始日志
  2. 存储降本:分层可以支持数据的生命周期管理。数据仓库中的数据通常具有不同的生命周期,分层可以帮助对数据进行更好地管理和归档,确保数据的可用性和长期保存。ADS层按需保留热数据,历史数据自动归档至冷存储(高频高价值数据用贵存储,低频低价值数据用贱存储。对比:非分层模式下全量存储导致成本飙升300%)

 3. 工程效能提升

将数据仓库按照不同的层级进行划分,可以根据需求优化每个层级的性能,使数据的查询和分析更加高效。用空间换时间,数据存储持久化,减少重复开发,提高数据的复用性。比如将稳定且通用的加工逻辑下沉到某一层,下游在使用时可以直接引用,提高数据查询效率。

-- 分层前:每次分析需从原始日志开始关联维表
SELECT /*+ 消耗120 core-hours */u.province,COUNT(DISTINCT o.user_id) 
FROM raw_orders o 
JOIN raw_users u ON o.user_id = u.id  -- 原始表直接耦合
WHERE o.dt='2023-12-01';-- 分层后:直接使用DWS层聚合结果(仅消耗0.5 core-hours)
SELECT province, order_cnt 
FROM dws_province_order_daily  -- 预计算中间层
WHERE dt='2023-12-01';


4. 精细化权限控制

分层可以提供不同的数据访问方式和权限控制。将数据仓库分为不同的层级,可以根据用户的需求和权限将不同层级的数据暴露给用户,实现对数据的灵活访问和控制,同时确保敏感数据的安全性。
层级    访问角色    敏感数据处理方式
ODS    数据工程师    保留原始数据,RBAC强管控
DWD    分析师    已脱敏(如MD5处理身份证)
ADS    业务端APP    仅开放聚合指标


5. 迭代敏捷性增强

  1. 隔离变更影响:屏蔽原始数据的异常,避免造成数仓跟着大动作的修改,当ODS层表结构变动时,只需重构DWD→DWS层ETL,ADS层应用无感知
  2. 快速响应需求:减少重复开发,新业务接入可直接调用DWS层数据,交付周期从周级缩短至小时级


问题二. 数据仓库分层(层级划分),每层做什么?数据分层及定位

1. ODS层(Operational Data Store)

核心职责:原始数据接入与镜像存储

数据形态
与业务库同构(如MySQL表结构直导Hive)
Kafka流数据落地为Parquet文件
典型操作

-- Sqoop同步示例(保留delete标志位)
sqoop import \
--connect jdbc:mysql://db_ip/userdb \
--table orders \
--hive-import \
--hive-table ods.orders \
--delete-target-dir

关键特征
存储T+1全量快照(部分场景保留binlog增量日志)
建立基线分区:dt=yyyy-mm-dd
禁止业务直接访问(通过视图提供受限查询)

2. DWD层(Data Warehouse Detail)

核心职责:标准化清洗与维度融合

核心加工流程

具体任务
1. 数据质量加固
空值填充(如user_id缺失时置为-9999)
枚举值转换(将status_code映射为可读标签)
2. 维度退化

-- 订单事实表+商家维度退化
CREATE TABLE dwd.fact_order AS
SELECT o.order_id,o.amount,s.shop_name,  -- 退化维度字段s.city_level
FROM ods.orders o 
LEFT JOIN ods.shop s ON o.shop_id = s.id;


3. 敏感数据脱敏(身份证/MD5加密)

3. DWS层(Data Warehouse Summary)

核心职责:面向主题的轻度聚合

设计模式

模型类型适用场景示例
每日聚合高频通用指标日UV/PV、交易总额
累积快照多事件周期分析用户生命周期转化漏斗
拉链表缓慢变化维度追踪历史价格波动分析
--案例
-- 用户日粒度行为摘要表
CREATE TABLE dws.user_action_daily
PARTITIONED BY (dt STRING)
AS
SELECT user_id,COUNT(CASE WHEN event_type='click' THEN 1 END) AS click_cnt,SUM(dwell_time) AS total_duration
FROM dwd.event_detail
WHERE dt='${current_day}'
GROUP BY user_id;

核心价值
预计算减少80%重复聚合开销
统一原子指标口径(如DAU定义全局一致)

4. ADS层(Application Data Service)

核心职责:面向应用的灵活加工

技术特性
支持非范式存储(JSONB/Array列存储复杂结构)
动态冷热分离(近期数据存ClickHouse,历史数据归档至Iceberg)
接口化服务(通过Presto/Trino暴露HTTP API)

分层定位特征
ADS
应用数据层
  • 非公用性的、个性化指标加工。
  • 基于应用展现的多层汇总、数据组装。
  • 基于关键业务对象的全生命周期数据的打通。
  • 满足一些特定自定义查询、数据挖掘应用
  • 维度建模方法,星型模型设计。
  • 数据来源于DWD或DWS。
  • 基于应用的数据组装,如大宽表集市、横表转纵表、趋势指标串。满足前端报表查询、分析图表、仪表盘等应用。
  • 尽量减少数据访问时计算,优化检索
  • 事实拉宽,度量预先计算
  • 关键业务对象的全生命周期数据的高度融合,可包含业务的事实特征、统计特征、算法特征
DWS
汇总数据层
  • 沉淀公用、常用以及稳定的衍生/复合指标数据。
  • 沉淀常用的维度和粒度进行适度汇总。
  • 提供面向业务对象,面向各角色、全分析视角、跨主题的、整合拉通宽表
  • 维度建模设计方法、标准星型模型。
  • DWS层数据来源于DWD层。
  • DWS层保持相对稳定,业务驱动,随着分析需求的增加,需要进行不断扩展。
  • 设计面向分析对象的宽表,整合拉通跨主题、汇总指标,对业务对象打标签,支撑360全视角分析。
  • 加强指标的维度退化,采取更多宽表化的手段构建公共指标,提升公共指标的复用性,减少重复的加工。
DWD
明细数据层
  • 面向主题的,提供最细粒度的、完整业务属性的、历史可追溯的公共原子数据。
  • 提供主题内的、整合拉通明细数据(join,非汇总),包含面向业务对象,跨主题的、整合拉通的明细宽表
  • 维度模型设计,围绕企业核心业务过程展开,关注业务过程中的核心业务事件和业务实体。
  • 业务主题的划分遵从企业级数据模型的划分。
  • 模型对标签+的业务过程,保存最完整的、最细粒度、历史的数据。
  • 维度/事实可保留历史变化。
  • 对数据作标准化、格式转换、清洗过滤、空值处理、数据分割合并等清洗处理,作为数据仓库唯一的可靠、可信、准确的数据源。
  • 数据表名、字段命名规范化,统一数据类型定义。
  • 面向分析对象的明细宽表,以分析对象+业务标签为架构构建,提升DWR模型数据共享性
ODS
贴源数据层
  • 统一接入业务系统数据,是交易系统和数据仓库之间的数据缓冲区。
  • 贴源数据,为DW数据加工提供原材料
  • 物理模型和业务系统模型一致。
  • 业务数据不做数据清洗转换,保持原样。
  • 业务数据优先sooop方式集成。
  • 关键数据要求记录删除标记

问题三. 数仓建模的流程?维度建模的步骤,如何确定这些维度的

一、数仓建模核心流程

  1.  **业务需求锚定** - 深度对齐业务目标(如电商关注「交易转化率」「用户复购周期」) - 识别关键业务过程(订单创建、支付成功、物流签收)。与业务方进行用例风暴(例:电商促销效果分析需追踪「优惠券核销率」「跨品类购买关联」;识别关键指标计算口径(如GMV是否排除取消订单)
  2. 概念模型设计(领域模型抽象)

    1. 划分主题域(用户域、商品域、交易域),划分核心实体(用户、商品、渠道)及事件(浏览、下单、支付)
    2. 明确跨域数据关联规则(例:用户画像与商品偏好矩阵的连接键)
    3. 定义实体关系:1:1 / 1:N / M:N(例:用户与收货地址的1:N关系)
  3. 逻辑模型构建

    1. 选择建模方法论:维度建模(Kimball)/ 范式建模(Inmon)
    2. 制定数据分级存储策略(热温冷数据生命周期)
  4. 物理模型实施

    1. 库表结构定义(分区键、分桶策略、压缩算法)
    2. 存储引擎选型(Hive/ClickHouse/Doris)
  5. 数据管道开发

    1. ETL链路配置(增量合并策略、幂等性保障)
    2. 数据质量监控(波动阈值告警、主键唯一性校验)

二、维度建模四步法(Kimball方法论)

STEP 1:选定业务过程

-- 示例:电商核心业务过程 • 用户注册 --> dim_user • 商品曝光 --> fact_impression • 加购行为 --> fact_cart • 订单支付 --> fact_order

STEP 2:声明事实表粒度
  • 原子粒度原则:每条记录对应业务最小操作单元
    ✅ 有效案例:订单事实表以 单个SKU粒度 存储
    ❌ 错误案例:按小时聚合销量(损失明细追溯能力)
STEP 3:维度拆解
维度类型作用典型字段
退化维度直接嵌入事实表订单编号/物流单号
角色扮演维度同一维度多场景复用时间维度(支付/发货时间)
缓慢变化维度处理渐变属性用户会员等级

维度确定方法:

  1. 业务调研:收集运营常用筛选条件(城市、渠道、品类)
  2. 现有报表反推:分析BI系统中高频分组字段
  3. 公共维度总线:跨业务线统一维度定义(如地理维度标准)
STEP 4:事实量化
事实类型计算特性示例
可加事实所有维度均可累加销售额/商品数量
半可加事实仅特定维度可聚合账户余额(不可跨时间加)
不可加事实必须依赖比率计算折扣率/毛利率

问题四. 怎么解决hive中的数据倾斜问题?

  1. 使用Map端聚合:在Hive中,可以通过设置hive.map.aggr=true来开启Map端聚合,这样可以在Map阶段进行部分聚合,减少Reduce阶段的数据量。
  2. 增加Reduce任务数:通过调整mapred.reduce.tasks参数(或者Hive中的hive.exec.reducers.bytes.per.reducer)来增加Reduce任务的数量,使每个Reduce任务处理的数据量更均匀。
  3. 对倾斜Key进行特殊处理: a. 单独处理倾斜Key:将倾斜的Key单独拿出来处理,然后再和其他数据合并。 b. 随机前缀法:在Group By或Join时,对倾斜的Key添加随机前缀,使得原本一个Key的数据分散到多个Reduce任务中,然后再进行聚合或去前缀处理。
  4. 使用SMB Join(Sort-Merge-Bucket Join):如果表是分桶且排序的,可以使用SMB Join来避免数据倾斜。
  5. 使用Skew Join优化:在Hive 0.10.0之后,可以通过设置hive.optimize.skewjoin=true来开启Skew Join优化。当某个Key出现倾斜时,Hive会自动将倾斜的Key分到多个Reduce任务中处理。

Hive数据倾斜的本质是分布式哈希的局限性。据实践经验,采用分桶表+自动优化的组合方案可在不改写业务逻辑前提下解决85%倾斜问题,剩余15%需结合业务特性和盐值策略精细化处理。

引擎级优化参数集

-- 核心参数组合(写入hive-site.xml或session级设置)
SET hive.exec.parallel=true;                  -- 开启任务并发
SET hive.exec.parallel.thread.number=16;      -- 并发线程数
SET hive.optimize.skewjoin=true;              -- 自动处理Join倾斜
SET hive.skewjoin.key=100000;                 -- 超过10w条相同key即判定倾斜
SET hive.optimize.skewjoin.compiletime=true;  -- 编译时识别倾斜
SET hive.groupby.skewindata=true;             -- GroupBy倾斜优化
SET mapred.reduce.tasks=200;                  -- 动态调整Reduce数量

下面我将针对不同场景给出具体解决方案,包括代码示例。

场景1:GROUP BY 倾斜(如null值占比超40%)
--方案1:两阶段聚合(局部聚合+全局聚合)SELECT key, SUM(cnt) AS total 
FROM ( 
SELECT key, CAST(RAND() * 10 AS INT) AS salt, -- 添加随机盐值 COUNT(1) AS cnt 
FROM source_table GROUP BY key, salt -- 第一阶段带盐值聚合 
) tmp GROUP BY key; -- 第二阶段去盐值聚合 -- 🟢方案2:自动倾斜处理(Hive 2.3+)SET hive.groupby.skewindata=true; -- 开启自动优化SELECT key, COUNT(1) FROM table GROUP BY key;

场景2:JOIN 倾斜(大卖家关联订单表)
-- 🟢 方案1:MapJoin强制广播小表
SET hive.auto.convert.join=true;        -- 开启自动MapJoin
SET hive.mapjoin.smalltable.filesize=25000000; -- 小表阈值25MB/* 手动指定MapJoin */
SELECT /*+ MAPJOIN(small_table) */ large_table.id, small_table.name
FROM large_table 
JOIN small_table ON large_table.id = small_table.id;-- 🟢 方案2:分桶Join(需预先分桶)
CREATE TABLE orders_bucketed (order_id BIGINT,seller_id BIGINT
) CLUSTERED BY (seller_id) INTO 128 BUCKETS;-- 启用分桶Join优化
SET hive.optimize.bucketmapjoin=true;
SET hive.optimize.bucketmapjoin.sortedmerge=true;SELECT /*+ MAPJOIN(s) */ o.*, s.seller_name
FROM orders_bucketed o 
JOIN seller_bucketed s ON o.seller_id = s.seller_id;
场景3:NULL值倾斜(空key聚集)
-- 🧂 NULL值特殊处理方案
SELECT COALESCE(key, CONCAT('NULL_', CAST(RAND()*100 AS STRING))) AS new_key,value
FROM source_table;-- 最终聚合时还原
SELECT CASE WHEN new_key LIKE 'NULL_%' THEN NULL ELSE new_key END AS orig_key,SUM(value)
FROM tmp_table
GROUP BY new_key;
场景4:动态分区写入倾斜
-- 危险的分区写入
INSERT OVERWRITE TABLE sales PARTITION(dt)
SELECT ..., dt FROM source;-- 修复方案:两阶段写入
SET hive.optimize.sort.dynamic.partition=true;
SET hive.exec.dynamic.partition.mode=nonstrict;

问题五. 怎么定位hive中的数据倾斜问题?

▶步骤1:抓取慢任务日志
# 获取YARN应用日志
yarn logs -applicationId application_123456789_0001 > app.log# 提取关键统计指标
grep -A20 "Counters:" app.log | grep -E 'RECORDS_OUT|FILE_BYTES_READ'

典型倾斜日志

Reducer 2 RECORDS_OUT_INTERM: 3,452,178
Reducer 3RECORDS_OUT_INTERM: 128  # ← 异常低值
Reducer 4 RECORDS_OUT_INTERM: 5,892,361  # ← 异常高值
▶ 步骤2:分析执行计划定位高危操作
EXPLAIN EXTENDED
SELECT user_id, count(*) 
FROM orders 
GROUP BY user_id;  -- 风险点:GROUP BY字段-- 查看执行计划中的关键节点
_STAGE PLANS:Reducer 2:  # 关注Reducer数量Group By Operator:  # 高风险操作位置keys: user_id (type: string)
▶ 步骤3:采样可疑字段分布
-- 快速定位热点Key(替换your_table和key_column)
WITH distribution AS (SELECT key_column, COUNT(1) AS cnt FROM your_table GROUP BY key_column ORDER BY cnt DESC LIMIT 10
)
SELECT key_column,cnt,ROUND(cnt/(SELECT SUM(cnt) FROM distribution),3)*100||'%' AS ratio 
FROM distribution;

输出样例

user_id cnt ratio

null 4508923 41.2% -- 空值倾斜

0 3201654 29.3%

123456 89562 0.8%

▶ 步骤4:动态调试验证
-- 方法1:添加随机前缀打散数据
SELECT /*+ MAPJOIN(b)*/ a.user_id, b.order_info
FROM (SELECT *, concat(user_id, '_', floor(rand()*10)) as join_key FROM users 
) a JOIN orders b ON a.join_key = b.join_key;-- 方法2:分桶预处理
CREATE TABLE user_bucketed 
CLUSTERED BY(user_id) INTO 100 BUCKETS 
AS SELECT * FROM users;

http://www.dtcms.com/a/395466.html

相关文章:

  • 深入理解Java中的==、equals与hashCode:区别、联系
  • Qt笔记:QString::toLocal8Bit的理解
  • 第12章 机器学习 - 局限性
  • ​​[硬件电路-320]:模拟电路与数字电路,两者均使用晶体管(如BJT、MOSFET),但模拟电路利用其线性区,数字电路利用其开关特性。
  • 今日行情明日机会——20250922
  • 智能交通拥堵检测系统详解(附视频+代码资源)
  • LLM 数据安全:筑牢数据防线
  • AI 在医疗领域的十大应用:从疾病预测到手术机器人
  • 零序电流/电压(面向储能变流器应用)
  • 【系统分析师】2024年上半年真题:综合知识-答案及详解(回忆版)
  • 给工业通信装“耐达讯自动化翻译器”:电表说Modbus,主控听Profibus,全靠它传话
  • 不同品牌PLC如何接入云平台?御控多协议物联网网关一站式集成方案
  • 深入理解指针(最终章):指针运算本质与典型试题剖析
  • SCI 期刊验证!苏黎世大学使用 ALINX FPGA 开发板实现分子动力学模拟新方案
  • C# OnnxRuntime yolov8 纸箱分割
  • SQLite3的API调用实战例子
  • LeetCode 60. 排列序列
  • springboot2.7.11 + quartz2.3.2,单机,集群实战,增删改查任务,项目一启动就执行任务
  • Hive 调优
  • 王晨辉:RWA注册登记平台赋能资产数字化转型
  • 周末荐读:美 SEC 推出加密货币 ETF 上市标准,Base 发币在即
  • HTTP API获取 MQTT上报数据
  • Apache HTTP基于端口的多站点部署完整教程
  • 新网站如何让百度快速收录的方法大全
  • 企业非结构化数据治理与存储架构优化实践探索
  • dagger.js 实现嵌套路由导航:对比 React Router 的另一种思路
  • React自定义同步状态Hook
  • 系统架构设计能力
  • 安卓图形系统架构
  • 《ZooKeeper终极指南》