数仓面经总结
美团
拉链表的制作,数据量有多少,为什么不用快照表呢
- 拉链表会跟踪每个维度的变化,包括每次修改的历史,包含开始时间、结束时间、当前记录标识等字段
- 快照表只保留某个特定时刻的维度数据快照,不追踪变更,仅包含某个时间点的数据
数仓分层有哪些,具体做了什么,数仓分层作用
- 数仓分层架构包括ods、dwd、dwm、dws、ads
- ODS层是接入层,从数据源(api、数据库等)将数据同步到数仓中,中间不做任何处理操作
- DWD层是明细层,对ODS层的数据进行清洗、关联、转换、维度退化、建设主题域等操作
- DWM层是轻度汇总层,是DWD和DWS层的过渡层次,对DWD层的生产数据进行轻度汇总和汇总统计,把复杂指标前置处理,提升公共指标的复用性,减少重复加工
- DWS层汇总层,按主题域、颗粒度(如买卖家)划分,按照周期粒度、维度聚合,形成字段较多的宽表,用于提供后续的业务查询和应用。更重要的是要在DWS层完成指标口径统一和沉淀
- ADS层是应用层,按照应用域,颗粒度划分(如买卖家)划分,按照应用主题将对应的数据标签补充至应用层,形成用户画像或专项应用
- 价值:分层的核心就是以空间换时间
- 使数据更清晰,简化复杂问题。将复杂需求简单化拆解成多个步骤解决,每层去完成各自对数据的处理
- 减少重复开发,提升开发效率。通过大量的预处理,建设数仓中间层,提高数据复用性
- 数据血缘追踪,便于定位问题。分层能够清晰表和任务的上下游,知道下游哪个模块在使用,便于排查问题和后期维护
怎么设计表,怎么建模,DIM
- 表的设计
- 符合业务需求
- 数据冗余与性能优化:数据冗余有时是为了查询性能的优化,比如通过预先计算一些聚合数据,减少实时计算的压力
- 规范化与反规范化:在设计时,常常需要权衡规范化(减少冗余,避免数据重复)与反规范化(提高查询效率)之间的平衡
- 数仓建模
- 星型模型
- 以事实表为中心,所有维度直接关联在事实表上,这里的维表通常是未规范化的,有较大的冗余,这样可以减少表的关联,提高查询效率
- 雪花模型
- 雪花模型是星型模型的基础之上,维表又关联了其他维表,这里的维表通常是规范化的,减少了冗余,但是维护成本高,性能较差。如果以Hadoop体系来建设数仓,减少join就是减少shuffle
- 星型模型
- DIM表的设计
- 包含业务属性
- 历史数据跟踪,可以采用拉链表的方式
- 避免过度冗余:虽然维度表可能会进行反规范化,以提高查询效率,但也需要避免过度冗余,影响存储空间和数据更新
- 设计唯一标识:每个维度表应该有一个唯一标识符,通常是维度表的主键
什么是数据倾斜,数据倾斜的解决方案
- 数据倾斜
- 数据倾斜根本问题存在于key的分布不均,在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或join等操作。此时如果某个key对应的数据量特别大的话,就会发生数据倾斜
- 解决方案
- 设置参数
- 开启map join,合并小文件,设置Map|Reduce内存,用Spark3计算引擎
- Map阶段层面
- 剪裁列和剪裁行,减少全表、全字段查询
- 查询带分区字段
- distribute by rand(),用来控制map输出结果的分发,保证每个分区的数据量基本一致
- Reduce阶段层面
- 将distinct 改成 group by
- 笛卡尔积优化
- 先过滤在计算
- 将大key打上随机值计算,再去除进行重组
- map join
- map join会把小表全部读入内存中,在map阶段直接拿另外一个表的数据和内存中表数据做匹配,由于在map是进行了join操作,省去了reduce运行的效率也会高很多,mapjoin还有一个很大的好处是能够进行不等连接的join操作,如果将不等条件写在where中,那么mapreduce过程中会进行笛卡尔积,运行效率特别低,如果使用mapjoin操作,在map的过程中就完成了不等值的join操作,效率会高很多
- 小文件优化
- 对于分区较多使用Spark3进行动态分区刷新
- 对千分区较少或未分区的表采用重建表,补数据方法回刷
- z-order
- Spark3切换使用aqe
- 设置参数
Spark的shuffle流程是怎么样的
- Spark 任务在RDD 之间存在宽依赖时,就会触发 Shuffle。这些操作会导致数据需要重新分区,从而在不同的 Executor 之间传输数据,这就是 Shuffle 过程,Spark Shuffle 主要分为两个阶段
- Map端
- 根据 Key 计算目标分区 ID
- 数据写入内存缓冲区,当缓冲区满时触发溢写
- 溢写时数据进行排序或直接写入
- 数据写入磁盘,并为每个 Reduce 任务生成索引文件
- Reduce端
- Reduce 端任务会通过 HTTP 请求,从所有 Map 任务所在的节点上获取对应分区的数据
- 合并数据
- 如果使用的是 Sort Shuffle,数据会按照 Key 进行排序
- 执行后续计算
Shuffle有哪几种类型
- Hash Shuffle
- 适用于小规模数据集,每个 Map 任务会为每个 Reduce 任务创建一个文件
- 容易导致小文件过多,影响性能
- 大规模数据处理时,磁盘 I/O 开销大
- Sort Shuffle(默认)
- 适用于大数据量场景,减少 Shuffle 过程中的小文件问题
- Map 端数据在写入磁盘前按照分区 ID 进行排序,并存入单个文件
- Bypass Merge Shuffle
- 适用于小规模分区(小于 200 个分区)
- 避免排序,提高效率
在shuffle的过程中会进行排序吗,有哪几种排序
Map端
- 在 Sort Shuffle 过程中,Map 任务在写入数据之前,会按照 Key 和分区 ID 进行排序
- 内存中的排序:Tim-Sort(归并排序优化)
- 如果数据量过大,则溢写到磁盘,如果有多个溢写文件,采用 External Merge Sort 合并数据,最终生成一个大文件。
- 在 Sort Shuffle 过程中,Map 任务在写入数据之前,会按照 Key 和分区 ID 进行排序
Reduce端
- Reduce 任务在拉取多个 Map 任务的数据后,会对数据进行合并和排序,以便进行聚合或 Join 操作
- 归并排序(如果多个 Map 任务的数据块太多,会采用多路归并)
- Reduce 任务在拉取多个 Map 任务的数据后,会对数据进行合并和排序,以便进行聚合或 Join 操作
什么是快速排序,时间复杂度是多少,手撕快排代码题
- 时间复杂度:O(nlog)
1 |
|
Spark是如何划分stage阶段
- 生成DAG有向无环图之后,从最后一个rdd往前推,先创建一个stage,它是最后一个stage
- 如果遇到了窄依赖就把该rdd加入到stage中,如果遇到了宽依赖,就从宽依赖切开,最后一个stage也就划分结束了
- 后面重新创建一个新的stage,还是按照第二步操作继续往前推,一直推到最开始的rdd,整个划分stage也就结束了
Spark SQL的执行流程,如何将一个SQL语句转换为任务
SQL 查询 → 解析树(解析)
- SQL 字符串被解析成 抽象语法树
解析树 → 逻辑计划(分析)
- 对解析树进行语法和语义分析,生成 逻辑计划
逻辑计划 → 优化后的逻辑计划(逻辑优化)
- 通过应用优化规则,生成优化后的 逻辑计划
优化后的逻辑计划 → 物理计划(物理规划)
- 生成多个物理执行计划,选择最优的执行策略
物理计划 → 代码生成(代码生成)
- 生成高效的 Java 字节码,减少运行时开销
代码生成 → 执行任务(执行)
- 将任务分配到 Spark 集群的 Executor,进行并行计算,最终返回结果
宽窄依赖,宽依赖阶段会发生什么
窄依赖(Narrow Dependency):每个子RDD的一个分区只依赖于父RDD的一个或少数几个分区,可以直接在同一个Stage 内计算,不会触发Shuffle
宽依赖(Wide Dependency):子RDD的一个分区可能依赖多个父RDD的分区,需要跨节点拉取数据(Shuffle),因此会触发新的 Stage
中科智泓
如果直接筛,可能导致被锁住,有其他办法么
- insert overwrite
- 创建临时表,存储去重后的数据,再将该表覆盖到原表
- 如果查询慢,考虑数据倾斜,可以用distribute by rand(),提高并行度,这样做的优势是可以避免reduce任务超载,更均匀的分配数据
SQL中几种删除方式的区别
- delete,是按条件进行删除适合关系型数据库
- drop,是直接删除表结构+表数据
- insert overwrite,hive不支持delete,不会锁表性能更高
事实表和维度表有什么区别
- 事实表的数据量大,其中包含度量数据(如销售额、库存数量、交易金额等)和外键,这些外键与维度表相连
- 维度表的数据量比较小,包含的是描述性属性,例如日期、客户名称、产品类型等
Hive和Spark有什么区别
- Hive 是一个数据仓库工具,主要用于数据的存储、查询和分析。它建立在 Hadoop 之上,提供一个类似 SQL 的查询语言,用于批处理大数据
- Spark是一个分布式计算框架,它是基于内存计算的,速度比Hive用MapReduce作为计算引擎更快
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Pencil!
评论