分桶表的介绍和作用
一、分桶表的基本介绍
1、什么是分桶表?
分桶表主要是用于分文件的,在建表的时候,指定按照那些字段执行分桶操作,并可以设置需要分多少个桶,当插入数据的时候,执行MR的分区的操作,将数据分散各个分区(hive分桶)中,默认分发方案是:hash 取模
注意:对于分桶表,不能使用load data 的方式进行数据插入操作,因为load data 导入的数据不会有分桶结构
2、什么是分区表?
分区表是数据库中一种特殊的表结构设计,它将数据按照预定义的规则分散存储在多个物理区域(称为 “分区”)中,但对用户来说逻辑上仍然是一个整体表。分区表在逻辑上是一张表,但数据在物理上被拆分为多个独立的存储单元(如文件、文件夹或索引)。用户无需关心数据具体存储在哪个分区,只需像操作普通表一样查询即可。分区的目的是提高查询性能、简化数据管理(如数据归档、删除),尤其适用于数据量极大的表。
3、分桶表和分区表的区别:
1)分桶对数据的处理比分区更加细粒度化;分区针对的是数据的存储路径;分桶针对的是数据文件;
2)分桶是按照列的哈希函数进行分割的,相对比较平均;而分区是按照列的值来进行分割的,容易造成数据倾斜;
3)分桶和分区两者互不干扰,可以把分区表进一步分桶
4)简单来说,分区就是把表分成一个一个文件夹,一个文件夹里面还可以在放文件夹,分桶是把表分成一个一个文件,文件里面就不能在放文件,所以分区可以分好几层,分桶不可以
4、如何构建一个分桶表?
create table test_buck(id int, name string)
clustered by(id) sorted by (id asc) into 6 buckets -- 创建分桶表的SQL
row format delimited fields terminated by '\t';
5、如何向分桶表添加数据?
标准格式:
1)创建一张与分桶表一样的临时表,唯一区别是这个表不是一个分桶表
2)将数据加载到这个临时表中
3)通过insert into + select 语句将数据导入到分桶表中
注意:sqoop不支持直接对分桶表导入数据
二、分桶表有什么作用
1、进行数据采样
案例1: 数据质量校验工作(一般会先判断各个字段数据的结构信息是否完整)
案例2: 在进行数据分析的时候, 一天需要编写N多条SQL, 但是每编写一条SQL后, 都需要对SQL做一个校验, 如果直接面对完整的数据集做校验, 会导致校验时间过长, 影响开发进度, 此时可以先采样出一部分数据
案例3: 在计算一些比率值,或者 在计算相对指标的时候, 也会基于采样数据来计算相对指标
比如: 计算当前月的销售额相对上个月 环比增长了百分之多少?
可以选择当前月和上个月抽取出百分之30的数据, 基于这个数据来计算
重点:如何进行数据采样
采样函数: tablesample(bucket x out of y on column)
放置位置: 紧紧放置表的后面 如果表有别名 必须放置别名的前面
例如:select * from 表 tablesample(bucket x out of y on column) 表的别名;
说明:
x: 从第几个桶开始进行采样
y: 抽样比例(总桶数/y=分多少个桶)
column: 分桶的字段, 可以省略的
注意:
x 不能大于 y
y 必须是表的分桶数量的倍数或者因子
案例:
1) 假设 A表有10个桶, 请分析, 下面的采样函数, 会将那些桶抽取出来
tablesample(bucket 2 out of 5 on xxx)
会抽取几个桶呢? 总桶 / y = 分桶数量 10/5=2
抽取第几个编号的桶? (x+y)
2,7
2) 假设 A表有20个桶, 请分析, 下面的采样函数, 会将那些桶抽取出来
tablesample(bucket 4 out of 4 on xxx)
会抽取几个桶呢? 总桶 / y = 分桶数量 20/4=5
抽取第几个编号的桶? (x+y)
4,8,12,16,20
tablesample(bucket 4 out of 40 on xxx)
会抽取几个桶呢? 总桶 / y = 分桶数量 20/40=0.5
抽取第几个编号的桶? (x+y)
抽4.5,只抽一个
2、提升查询的效率(单表|多表)
单表
不分桶就只能从头到尾一个一个慢慢查,而分桶之后先得到桶编号,在根据桶编号进入对应的桶查询数据即可
多表
分为小表和大表、中型表和大表、大表和大表
Reduce 端 join:是在 MapReduce 框架下,针对表连接(如将两个或多个数据表依据关联键合并)这一特定操作的实现方式,是一种具体的业务处理策略 ,专注于解决数据关联问题。
reduce端join的流程:
Map 阶段:读取不同表的数据,为每行数据添加标记以区分来源表,并将数据转换为 <Join Key, Value>
形式输出。例如,对于订单表和用户表,以关联键(如用户 ID)为 Join Key,为来自订单表的数据标记 tag = order
,来自用户表的数据标记 tag = user
。
Shuffle 阶段:与 MapReduce 的 Shuffle 类似,根据 Join Key 的哈希值将数据分发到对应的 Reduce 节点,保证相同 Join Key 的数据汇聚到一处。
Reduce 阶段:根据数据标记区分不同表的数据,然后执行表连接操作(如内连接、左连接等),生成最终的连接结果。
可能出现的问题:
1) 可能出现数据倾斜的问题
2) 导致reduce压力较大
小表和大表
采用 map join的方案
在进行join的时候, 将小表的数据放置到每一个读取大表的mapTask的内存中, 让mapTask每读取一次大表的数据都和内存中小表的数据进行join操作, 将join上的结果输出到reduce端即可, 从而实现在map端完成join的操作
如何开启map Join
set hive.auto.convert.join=true; -- 是否开启map Join
set hive.auto.convert.join.noconditionaltask.size=512000000; -- 设置小表最大的阈值(设置block cache 缓存大小)
中型表和大表
中型表: 与小表相比 大约是小表3~10倍左右
解决方案:
1) 能提前过滤就提前过滤掉(一旦提前过滤后, 会导致中型表的数据量会下降, 有可能达到小表阈值)
2) 如果join的字段值有大量的null, 可以尝试添加随机数(保证各个reduce接收数据量差不多的, 减少数据倾斜问题)
3) 基于分桶表的: bucket map join
bucket map join的生效条件:
1) set hive.optimize.bucketmapjoin = true; --开启bucket map join 支持
2) 一个表的bucket数是另一个表bucket数的整数倍
3) bucket列 == join列
4) 必须是应用在map join的场景中
注意:如果表不是bucket的,则只是做普通join。
就是把中型表分桶变成小表,在通过小表和大表的方法即可
大表和大表
大表: 与小表相比 大约是小表10倍以上
核心原理
分桶:两个表按 相同的 Join Key(如 user_id
)哈希分桶(例如都分为 100 个桶),确保相同 Join Key 的数据在对应桶中。
排序:每个桶内的数据按 Join Key 排序,便于快速匹配。
Map 端计算:Join 时,Map 任务直接读取两个表的对应桶,用 归并排序 算法逐行匹配,无需 Shuffle。
解决方案:
1). 能提前过滤就提前过滤掉(减少join之间的数量, 提升reduce执行效率)
2). 如果join的字段值有大量的null, 可以尝试添加随机数(保证各个reduce接收数据量差不多的, 减少数据倾斜问题)
3). SMB Map join (sort merge bucket map join)
实现SMB map join的条件要求:
1) 一个表的bucket数等于另一个表bucket数(分桶数量是一致,一对一的关系)
2) bucket列 == join列 == sort 列
3) 必须是应用在bucket map join的场景中,也就是已经开启了bucket map join的相关参数
4) 开启相关的参数:
-- 开启SMB map join
set hive.auto.convert.sortmerge.join=true;
set hive.auto.convert.sortmerge.join.noconditionaltask=true;
--写入数据强制排序
set hive.enforce.sorting=true;
set hive.optimize.bucketmapjoin.sortedmerge = true; -- 开启自动尝试SMB连接