数据仓库面试题整理(一)
面试题整理
- 一、数据仓库基础
- 1.范式建模和维度建模
- 2.主题域划分
- 3.数据仓库分层优点
- 4.事实表分类
- 5.缓慢变化维
- 6.数据输出SLA保障
- 7.大表JOIN大表优化
- 二、Hive基础
- 1.HIVE SQL优化
- 2.Hive Join类型
- 3.Hive Map和Reduce个数
- 4.Hive Map和Reduce的Shuffle过程
- 5.Hive JOIN,GROUPBY过程
- 1.JOIN
- 2.GROUP BY
- 6.Hive SQL2MR
- 7.HIVE 分区和分桶
- 1.分区
- 2.分桶
- 三、常见Hive SQL面试题
- 1.连续登陆
- 2.N日留存
- 3.共同好友
- 4.中位数
- 5.波峰波谷
一、数据仓库基础
1.范式建模和维度建模
a.范式建模
ER建模是数仓之父Bill Inmon推崇的一种“自上而下”的模型设计方式,及无需考虑具体数据支持应用是哪些,而是从整个企业的数据入手,分析业务场景应该有什么样的数据,从而构建唯一的数据中心。
b.维度建模
维度建模是数仓专家Ralph Kimball推崇的一种“自下而上”的模型设计方式,及根据具体需求加载所需的数据,从业务实际需求入手进行数据建模。
如上所述,维度建模会将数据仓库的表划分为事实表(A与B等实际发生的业务流程)和维度表(单一主键下对实体的描述)两种,如交易行为表和用户维度表。
a)星型模型由一个事实表与一组维度表组成,维度表中存在该维度下所有数据,所以会存在重复,如城市维中的各区县所属的城市,实际上是会重复使用和定义的。建模流程上会以明确业务过程为起始,其次是明确粒度与维度,事实(按照顺序进行梳理),关系明确后进行数据建模。
b)雪花模型由一个事实表与一个或多个维度表组成,但是雪花模型是对星型模型的拓展,将星型模型中的维度表层次化,每个维度可关联多个子维度,以子维度的方式减少数据重复的问题。
c)星型模型与雪花模型的关联与区别关联:雪花模型在一定程度上是星型模型的拓展,将星型模型中的不满足规范化设计的维度表规范化。区别:雪花模型符合业务逻辑与范式设计,避免了数据冗余,但是由于关联表的增多会降低性能;星型模型将维度聚合,属于反范式设计,以存储空间换取较少的关联表带来的性能提升。
2.主题域划分
a.主题域和业务过程
通过拆解和归并业务过程可以明确主题域,对业务的核心理解会左右主题的定义。
b.主题域和主题
主题是一个抽象概念,是对企业的信息数据进行综合、归类汇总用以分析使用的数据的抽象,每一个主题对应一个宏观的分析领域。
主题域是联系较为紧密的数据主题的集合。在处理一个业务中,实际上会是多个主题的交叉,比如用户和客户交叉产生的订单域,可以根据业务的关注点,将这些数据主题划分到不同的主题域。
3.数据仓库分层优点
数仓分层优点:
1.解耦数据开发过程,专人专事,降低出问题的风险的同时方便问题定位。
2.用空间换时间,用多人多步操作换取使用数据的高效性。
3.数据流向规范,避免循环依赖的发生,也是方便问题定位的方式。
4.统计计算口径,减少重复开发。
4.事实表分类
5.缓慢变化维
解决办法:
1.新数据覆盖旧数据(较为粗暴,适用于不关注数据变化的维度)
2.保存多条记录,并添加字段加以区分
3.保存多个字段,不同字段保存不同值(适用于变化不超过两次的维度)
拉链表是一种为了保留历史数据,又节省空间而设计的数据存储模式,可以使用拉链表辅助解决
6.数据输出SLA保障
7.大表JOIN大表优化
a.间接map join
通过拆分数据间接完成map join(限制行或列,特殊数据处理)
b.负载均衡
二、Hive基础
1.HIVE SQL优化
思想:1.尽量尽早地过滤数据,减少每个阶段的数据量2.尽量原子化操作,尽量避免一个SQL包含复杂逻辑, 可以使用中间表或CTE来完成复杂的逻辑3.小表要注意放在join的左边,否则会引起磁盘和内存的大量消耗4.如果union all的部分个数大于2,或者每个union部分数据量大,应该拆成多个insert into 语句,实际测试过程中,执行时间能提升50%5.了解数据特点,如果有join ,group by操作的话,要注意是否会有数据倾斜6.控制Map和Reduce数量方式:1.列裁剪2.分区裁剪3.left semi join替换in,exists4.mapjoin5.小文件合并6.负载均衡
2.Hive Join类型
a.Reduce Join
reduce join(shuffle join,common join)join输入为Map的输出,在Map端输出时用on关键字作为key,对其关联key进行hash后推送至不同的reduce以确保相同key在同一个reduce中(在该步骤中可以对输入key的来源进行打tag标记以标识数据来源)
b.Map Join
map join即将小表放在内存中,那么Hive可以在map端执行一次连接操作。从而省略常规所需的reduce过程(在shuffle过程中会有极大的消耗,跨机器的数据传输量非常大)
3.Hive Map和Reduce个数
map数量:map的数量应该由输入的文件数量与大小决定
1)如果一个任务有很多小文件(远小于块默认大小128MB),则每个小文件都会被当做一个块,此时我们就应该减少map数量。
2)如果一个任务的大小为接近128MB,但是字段信息数量很大,此时我们就应该增加map数量。
可以通过将文件进行拆分的方式增加map的数量。reduce数量:reduce的数量由map的输出文件大小决定,不指定reduce个数的前提下,hive会计算出一个reduce的个数。
1)reduce个数调整方式
每个reduce任务处理的数据量:hive.exec.reducers.bytes.per.reducer(默认为1000^3=1G)
每个任务最大的reduce数:hive.exec.reducers.max(默认为999)
计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)
调整reduce个数
2)reduce的个数在进行全局操作的时候只有一个reduce,并且无法被增加,如笛卡尔积,order by,没有group by的汇总操作。
4.Hive Map和Reduce的Shuffle过程
a.Map端Shuffle
1.写缓存:环形内存缓冲区执行溢出写
每个map任务对应的唤醒内存缓冲区和额定大小,如果缓冲内容达到阈值则创建溢出写文件
2.分区:partition
3.排序:sort
4.聚合:combiner
5.生成溢出写文件
6.合并:merge
b.Map端Shuffle
1.复制Map输出:copy
2.排序:sort
3.合并:merge
5.Hive JOIN,GROUPBY过程
1.JOIN
Map阶段
将关联字段作为Key,Value Table标记,并对Table进行标记
Shuffle阶段
该阶段会根据key进行sort排序,然后分配给不同的reduce去执行下一步操作
Reduce阶段
根据Shuffle出的不同key,可知会分配给两个Reduce,每个reduce会分遍历数据,将table标记不同的记录两两组合
2.GROUP BY
Map阶段
将分组字段作为Key,Value为该分组下的记录数量
Shuffle阶段
该阶段会根据key进行sort排序(一般是字典排序),然后分配给不同的reduce去执行下一步操作
Reduce阶段
根据Shuffle出的不同key分配
6.Hive SQL2MR
1.Antlr是一门解析语言,由其定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树(AST Tree)
2.遍历抽象语法树(AST Tree),抽象出查询的基本组成单元QueryBlock(QueryBlock包括三个部分:输入源,计算过程,输出,可以将QueryBlock简单理解为一个子查询),即将SQL进一步抽象与结构化,方便转化为MapReduce,将QueryBlock转换为Calcite的RelNode,进行Calcite优化(HIVE提供元数据,Calcite有默认的Rules)
3.遍历QueryBlock,翻译为执行操作树(Operator Tree,其基本操作符包括TableScanOperator,SelectOperator,FilterOperator,JoinOperator,GroupByOperator,ReduceSinkOperator)
4.逻辑层优化器进行执行操作树(Operator Tree)变换,合并不必要的ReduceSinkOperator,减少shuffle数据量
5.遍历OperatorTree,翻译为MapReduce任务
6.物理层优化器进行MapReduce任务的变换,生成最终的执行计划
7.HIVE 分区和分桶
1.分区
分区是表的部分列的集合,可以为频繁使用的数据建立分区,是对“分区列”(partition column)的值进行粗略划分的机制。
Hive中每个分区对应着表很多的子目录,将所有的数据按照分区列放入到不同的子目录中去。庞大的数据集可能需要耗费大量的时间去处理。
在许多场景下,可以通过分区的方法减少每一次扫描总数据量,这种做法可以显著地改善性能。
指定MapReduce任务在HDFS中指定的子目录下完成扫描的工作。
2.分桶
分桶是通过对指定列进行哈希计算来实现的,通过哈希值将一个列名下的数据切分为一组桶,并使每个桶对应于该列名下的一个存储文件。
在分区数量过于庞大以至于可能导致文件系统崩溃时,我们就需要使用分桶来解决。
分区中的数据可以被进一步拆分成桶,不同于分区对列直接进行拆分,桶往往使用列的哈希值对数据打散,并分发到各个不同的桶中从而完成数据的分桶过程,桶中的数据条数不一定相等。
哈希函数的选择依赖于桶操作所针对的列的数据类型。除了数据采样,桶操作也可以用来实现高效的Map端连接操作。
三、常见Hive SQL面试题
1.连续登陆
整体思路就是将不同的日期变为相同的日期便于对所谓的连续进行数据统计
1.原始数据构建方式与原貌如下:
//基础数据构建:
selectstack(13,'A','2020-12-30','A','2020-12-31','A','2021-01-01','B','2021-01-05','B','2021-02-06','B','2021-02-07','B','2021-02-08','C','2021-02-10','C','2021-02-14','C','2021-02-16','D','2021-02-11','D','2021-02-12','D','2021-02-13'
) as (user_name,login_date)
基础数据样貌:
user_name | login_date |
---|---|
A | 2020-12-30 |
A | 2020-12-31 |
A | 2021-01-01 |
B | 2021-01-05 |
B | 2021-02-06 |
B | 2021-02-07 |
B | 2021-02-08 |
C | 2021-02-10 |
C | 2021-02-14 |
C | 2021-02-16 |
D | 2021-02-11 |
D | 2021-02-12 |
D | 2021-02-13 |
2.初步处理如下:
SELECT user_name,login_date, row_number() OVER (PARTITION BY user_name ORDER BY login_date) as sub_date, date_sub(login_date, row_number() OVER (PARTITION BY user_name ORDER BY login_date)) AS flag_date
FROM (selectstack(13,'A','2020-12-30','A','2020-12-31','A','2021-01-01','B','2021-01-05','B','2021-02-06','B','2021-02-07','B','2021-02-08','C','2021-02-10','C','2021-02-14','C','2021-02-16','D','2021-02-11','D','2021-02-12','D','2021-02-13') as (user_name,login_date)
) t
处理结果:
user_name | login_date | sub_date | flag_date |
---|---|---|---|
A | 2020-12-30 | 1 | 2020-12-29 |
A | 2020-12-31 | 2 | 2020-12-29 |
A | 2021-01-01 | 3 | 2020-12-29 |
B | 2021-01-05 | 1 | 2021-01-04 |
B | 2021-02-06 | 2 | 2021-02-04 |
B | 2021-02-07 | 3 | 2021-02-04 |
B | 2021-02-08 | 4 | 2021-02-04 |
C | 2021-02-10 | 1 | 2021-02-09 |
C | 2021-02-14 | 2 | 2021-02-12 |
C | 2021-02-16 | 3 | 2021-02-13 |
D | 2021-02-11 | 1 | 2021-02-10 |
D | 2021-02-12 | 2 | 2021-02-10 |
D | 2021-02-13 | 3 | 2021-02-10 |
3.最终步骤:
SELECT user_name, COUNT(*) AS continuous_days
FROM (SELECT user_name,login_date, row_number() OVER (PARTITION BY user_name ORDER BY login_date) as sub_date, date_sub(login_date, row_number() OVER (PARTITION BY user_name ORDER BY login_date)) AS flag_dateFROM (selectstack(13,'A','2020-12-30','A','2020-12-31','A','2021-01-01','B','2021-01-05','B','2021-02-06','B','2021-02-07','B','2021-02-08','C','2021-02-10','C','2021-02-14','C','2021-02-16','D','2021-02-11','D','2021-02-12','D','2021-02-13') as (user_name,login_date)) t
) t
GROUP BY user_name, flag_date
HAVING COUNT(*) >= 3
处理结果:
user_name | continuous_days |
---|---|
A | 3 |
B | 3 |
D | 3 |
2.N日留存
整体思路就是通过自关联获取以左表为第一天的对应右表中的记录的条目数量
1.原始数据构建方式如下:
//基础数据构建:
selectstack(15,'A','2020-12-01','B','2020-12-01','C','2020-12-01','D','2020-12-01','A','2020-12-02','B','2020-12-02','C','2020-12-02','B','2020-12-03','C','2021-02-03','E','2021-02-03','F','2021-02-03','D','2021-02-03','A','2021-02-04','B','2021-02-04','G','2021-02-05'
) as (uid,first_date)
2.处理如下:
SELECT t0.first_date AS day, datediff(t1.next_date, t0.first_date) AS gap, COUNT(DISTINCT t0.uid) AS users
FROM (selectstack(15,'A','2020-12-01','B','2020-12-01','C','2020-12-01','D','2020-12-01','A','2020-12-02','B','2020-12-02','C','2020-12-02','B','2020-12-03','C','2021-02-03','E','2021-02-03','F','2021-02-03','D','2021-02-03','A','2021-02-04','B','2021-02-04','G','2021-02-05') as (uid,first_date)
) t0LEFT JOIN (selectstack(15,'A','2020-12-01','B','2020-12-01','C','2020-12-01','D','2020-12-01','A','2020-12-02','B','2020-12-02','C','2020-12-02','B','2020-12-03','C','2021-02-03','E','2021-02-03','F','2021-02-03','D','2021-02-03','A','2021-02-04','B','2021-02-04','G','2021-02-05') as (uid,next_date)) t1ON t0.uid = t1.uid
WHERE t1.next_date >= t0.first_dateAND datediff(t1.next_date, t0.first_date) < 15
GROUP BY t0.first_date, t1.next_date
处理结果:
day | gap | users |
---|---|---|
2020-12-01 | 0 | 4 |
2020-12-02 | 0 | 3 |
2020-12-03 | 0 | 1 |
2021-02-03 | 0 | 4 |
2021-02-04 | 0 | 2 |
2021-02-05 | 0 | 1 |
2020-12-01 | 1 | 3 |
2020-12-02 | 1 | 1 |
2020-12-01 | 2 | 1 |
3.共同好友
整体思路就是通过对共同好友进行整合考虑,反向思考
如下所述如果A,B,C作为本题的调查对象,那么定义他们为主角,第二列即为主角的朋友(通过lateral view后打散朋友们)
反向思考,那么朋友的共同主角就是拥有该朋友的主角群体
而后再把这个主角群体的对应朋友们聚合起来就是拥有共同好友的主角群体的共同好友了
1.原始数据构建方式如下:
//背景介绍:A有BCD三个好友,B有AC好友,C有ABD好友,统计共同好友个数
//基础数据构建:
selectstack(3,'A','B,C,D','B','A,C','C','A,B,D'
) as (people,friends)
2.处理如下:
- a.方式一
selectpeople2,concat_ws(',',collect_list(friend)) as common_friends
from(--friends_tmp_01自连接之后过滤,得到“好友,用户1,用户2”select a.friend,concat(a.people,'-',b.people) as people2from (SELECTpeople,friendFROM(selectstack(3,'A','B,C,D','B','A,C','C','A,B,D') as (people,friends)) tlateral view explode(split(friends,',')) tmp as friend) ainner join (SELECTpeople,friendFROM(selectstack(3,'A','B,C,D','B','A,C','C','A,B,D') as (people,friends)) tlateral view explode(split(friends,',')) tmp as friend) bon a.friend = b.friendwhere a.people < b.people
) x
group by people2
order by people2
- a.方式二
selectpeoples,concat_ws(',',collect_set(friend)) as friends,length(concat_ws(',',collect_set(friend))) as friends_num
from(selectfriend,concat_ws(',',collect_set(people)) as peoplesfrom(SELECTpeople,friendFROM(selectstack(3,'A','B,C,D','B','A,C','C','A,B,D') as (people,friends)) tlateral view explode(split(friends,',')) tmp as friend) tgroup by friend
) t
group by peoples
处理结果
people | friends | friends_num |
---|---|---|
B,A | C | 1 |
C,B | A | 1 |
C,A | B,D | 3 |
4.中位数
整体思路
1.原始数据构建方式如下:
2.处理如下:
selectuser_class,avg(score) as middle_score
from(select*,count(1) over(partition by user_class) as cnt,row_number() over(partition by user_class order by score) as nkfrom(SELECT stack(19,'A',9,'A',9,'A',9,'A',2,'A',2,'A',3,'A',9,'A',9,'A',9,'B',7,'B',7,'B',7,'B',7,'B',7,'B',7,'B',7,'B',7,'B',9,'B',10) as (user_class,score)) t
) t
where if(cnt%2=0,nk in(cnt/2,cnt/2+1),nk=(cnt+1)/2)
group by user_class
5.波峰波谷
整体思路
1.原始数据构建方式如下:
2.处理如下:
- a.方式一
selectstock_name,stats_date,stock_price,case when stock_price > lag_price and stock_price > lead_price then '波峰'when stock_price < lag_price and stock_price < lead_price then '波谷'else '其他' end as price_type
from(selectstock_name,stats_date,stock_price,lag(stock_price,1) over(partition by stock_name order by stats_date) as lag_price,lead(stock_price,1) over(partition by stock_name order by stats_date) as lead_pricefrom(selectstack(10, 'A','20210621','13', 'A','20210622','11', 'A','20210623','17', 'A','20210624','12', 'A','20210625','14', 'B','20210621','16', 'B','20210622','12', 'B','20210623','12', 'B','20210624','17', 'B','20210625','13') as (stock_name,stats_date,stock_price)) t
) t
数据仓库面试题整理(一)相关推荐
- 数据仓库面试题整理超详细
数据仓库面试题 文章目录 数据仓库面试题 数据仓库的定义? 数据仓库和数据库的区别? 如何构建数据仓库? 什么是数据中台? 数据中台.数据仓库.[大数据平台](https://so.csdn.net/ ...
- 数据仓库项目管理面试题整理
数据仓库项目管理面试题整理 搜了一下网络上都是一个主题一个网页,自己看了觉得不方便,所以整理到一起放上来方便自己看. 原文出自Jerome的BI博客,网址是http://www.chinabi.net ...
- 尚学堂Java面试题整理
博客分类: 经典分享 1. super()与this()的区别? - 6 - 2. 作用域public,protected,private,以及不写时的区别? - 6 - 3. 编程输出如下图形. ...
- 前端面试题整理-ing---kalrry
前端面试题整理-ing---kalrry 前言 一.Html/Css面试题 1. img中的alt和title的区别 2. rem/em/vw的区别 3. BFC 是什么 4. @media all ...
- 计算机组成算术流水线,计算机组成系统结构试题整理.doc
计算机组成系统结构试题整理 选择题(50分,每题2分,正确答案可能不只一个,可单选或复选) (CPU周期.机器周期)是内存读取一条指令字的最短时间. (多线程.多核)技术体现了计算机并行处理中的空间并 ...
- 2010 .NET面试题整理之基础篇
2010 .NET面试题整理之基础篇 zhuan 开篇语:对于已有工作经验的朋友,也许面试题已显得不怎么重要,但是如果你应聘的还仅仅是个普通的程序员,相信在很多的公司都还是会先拿出一套面试题,可能对整 ...
- android笔试题整理
笔试题整理 今天接到消息,说下个星期三.会陆陆续续的有公司来学校找暑假实习生.还没准备好啊,这就来啦?麻蛋 我慌的要死啊~ 1.Math.round(11.5)等于多少(). Math.round(- ...
- Java经典面试题整理及答案详解(八)
简介: Java经典面试题第八节来啦!本节面试题包含了进程.线程.Object类.虚拟内存等相关内容,希望大家多多练习,早日拿下心仪offer- 了解更多: Java经典面试题整理及答案详解(一) J ...
- Java经典面试题整理及答案详解(三)
简介: 以下是某同学面试时,面试官问到的问题,关于面试题答案可以参考以下内容- 上一篇:Java经典面试题整理及答案详解(二) Java面试真题第三弹接住!相信通过前两节的学习,大家对于Java多少有 ...
最新文章
- linux 书签管理工具,在书签管理工具中使用Ubuntu字体
- 用c语言编写一个2048 游戏,求c语言编写的2048游戏代码,尽量功能完善一些
- linux监控命令执行,你可能不知道的 即时监控 Linux 使用者执行指令的三种方法...
- qtcreator摄像头显示时间_三星Galaxy S11 +渲染器展现出巨大的相机凹凸和四边形曲面显示...
- access用扫描枪输入_判断是否扫码枪输入的通用函数源码
- MySQL----获取当前日期当月第一天,最后一天
- 如何解决 React 官方脚手架不支持 Less 的问题
- JSSE Java与SSL
- VS 2005 Beta2 Team Suite Edtion
- 非平稳时间序列突变检测 -- Bernaola Galvan分割算法
- 关于求极限对几个问题的思考和总结
- Qt开发笔记:OpenSSL库介绍、windows上mingw32版本的OpenSSL编译模块化
- Oracle学习网站总结
- 偏最小二乘法(PLS)Python代码
- 计算机日常故障DIY维修有哪些,电脑故障排除及优化完全DIY
- JQuery学习之路Part8:家族树操作(查找祖先、后代、兄弟同胞、绝对查找)【完结】
- 23家上市公司抢先机落地区块链应用,政务、金融领域成果最吸睛
- c++链表获取长度,链表翻转,查找链表倒数第K个节点以及中间点
- STM32学习总结——UART
- js根据公历日期求每天的天干地支